题目大意
题目链接
给出n(<=1e3)个城市的x,y坐标以及每个城市的人数, 这些城市的主人想建造最小生成树,这时候有个会魔法的道士说, 我可以让一条路权值为0, 求A/B的最大值, 其中A是权值为0的道路连接的城市的人数之和, B是最小生成树的权值。
分析
这题实在是太妙了, 果然还是要多刷题。
我们暴力遍历所有的边, 然后求 A/B的最大值就行了。
MST为最小生成树的权值和,p[i]为城市i的人数。
如果我们遍历的的边(u, v) 在最小生成树的生成树上, 那么就把这条边减去 ans = max(ans, (p[u] + p[v]) / (MST - w))
4
如果不在最小生成树上, 那么我们就删除u到v这个环的最长边(因为要让B越小越好嘛), 即 ans = max(ans, (p[u] + p[v]) / (MST - maxd[u][v]))
看到这是不是就想到次小生成树啦~
切忌, 用链式前向星会超时!用邻接矩阵就不会超时~
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include <bits/stdc++.h> using namespace std; typedef pair<double , int> P; const int N = 1e3 + 5; const int M = 1e4 + 5; int vis[N]; int n, m; void init() { memset(vis, 0, sizeof vis); } double ma[N][N]; int pre[N], used[N][N]; double maxd[N][N], dis[N]; double prim(int st) { priority_queue<P, vector<P>, greater<P> > q; memset(used, 0, sizeof used); double sum = 0; dis[st] = 0; int cnt_s = 0; pre[st] = 0; q.push(P(0, st)); while (!q.empty() && cnt_s < n) { double d = q.top().first;int u = q.top().second; q.pop(); if (vis[u]) continue; cnt_s++; sum += d; vis[u] = 1; used[pre[u]][u] = used[u][pre[u]] = 1; maxd[pre[u]][u] = maxd[u][pre[u]] = d; for (int i = 1; i <= n; ++i){ if(i == u) continue; int v = i; double w = ma[u][v]; if (vis[v]) maxd[u][v] = maxd[v][u] = max(maxd[v][pre[u]], dis[u]); if (!vis[v] && w < dis[v]) { dis[v] = w;pre[v] = u; q.push(P(dis[v], v)); } } } return sum; } int p[N]; double getSecondMST(double sum){ double ans = 0; for (int i = 1; i <= n; ++i){ for (int j = 1; j <= n; ++j){ if (i == j) continue; if (!used[i][j]) ans = max(ans, 1.0 * (p[i] + p[j]) / (sum - maxd[i][j])); else ans = max(ans, 1.0 * (p[i] + p[j]) / (sum - ma[i][j])); } } return ans; }
struct node{ int x, y; }a[N]; inline double disxy(node x, node y){ return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y)); } int main(){ int t; scanf("%d", &t); while(t--){ scanf("%d", &n); init(); for (int i = 1; i <= n; ++i) scanf("%d%d%d", &a[i].x, &a[i].y, &p[i]); for (int i = 1; i <= n; ++i){ dis[i] = 1e9; for (int j = 1; j <= n; ++j){ maxd[i][j] = 0; ma[i][j] = disxy(a[i], a[j]); } } double sum = prim(1); sum = getSecondMST(sum); printf("%.2f\n", sum); } return 0; }
|
恰似你一低头的温柔,较弱水莲花不胜寒风的娇羞, 我的心为你悸动不休。 --mingfuyan
千万不要图快——如果没有足够的时间用来实践, 那么学得快, 忘得也快。