题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4081
题目大意:
求一个图的生成树,
可以指定一条边为“魔法边”,使其边权变为0。
在此基础上,要求 “ '魔法边' 连接的两点的点权 / 生成树上其它边的边权" 最大。
算法:
首先,一定是在最小生成树上去掉一条边,然后在被分成的两部分间加上一条边。
因为把最小生成树去掉一条边的话,残留在两部分的生成树就是它们各自的最小生成树,否则把这条边加回来完全可以构成一个更优的最小生成树,矛盾。
然后我们枚举最小生成树上去掉的是哪条边,此时“生成树上其它边的边权",已经被确定。那么我们就直接在被分割出的两部分中各找一个点权最大的点连”魔法边“即可。
PS:1000个点的完全图跑krustal还是比较困难的,我写的prim。
代码如下:
#include <cstdio> #include <cstring> #include <cctype> #include <cstdlib> #include <ctime> #include <climits> #include <cmath> #include <iostream> #include <string> #include <vector> #include <set> #include <map> #include <list> #include <queue> #include <stack> #include <deque> #include <algorithm> #define inf 0x3f3f3f3f #define mp make_pair #define fi first #define nd second using namespace std; const int MAXN = 1100; int x[MAXN], y[MAXN], z[MAXN]; int m1[MAXN], m2[MAXN]; bool vis[MAXN]; vector <pair <int, pair <int, int> > > edge; vector <pair <int, int> > nedge; queue <int> q; vector <int> mm[MAXN]; priority_queue <pair <double, pair <int, int> > > pq; int n; double dis(int i, int j) { return sqrt((double)(x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j])); } int bfs(int s, int t) { memset(vis, 0, sizeof(vis)); vis[s] = true; while(! q.empty()) { q.pop(); } vis[s] = true; q.push(s); int tmp = 0; while(!q.empty()) { int x = q.front(); q.pop(); tmp = max(tmp, z[x]); for(int i = 0; i < mm[x].size(); i ++) { if(mm[x][i] == t) { continue; } if(vis[mm[x][i]]) { continue; } q.push(mm[x][i]); vis[mm[x][i]] = true; } } return tmp; } int main() { int cas; scanf("%d", &cas); while(cas --) { scanf("%d", &n); for(int i = 0; i < n; i ++) { scanf("%d %d %d", &x[i], &y[i], &z[i]); mm[i].clear(); } memset(m1, -1, sizeof(m1)); memset(m2, -1, sizeof(m2)); memset(vis, 0, sizeof(vis)); edge.clear(); nedge.clear(); while(! pq.empty()) { pq.pop(); } for(int i = 1; i < n; i ++) { pq.push(mp(-dis(i, 0), mp(i, 0))); } vis[0] = true; double sum = 0.0; while(! pq.empty()) { int y = - pq.top().fi; int x = pq.top().nd.fi; int p = pq.top().nd.nd; pq.pop(); if(vis[x]) { continue; } vis[x] = true; mm[x].push_back(p); mm[p].push_back(x); nedge.push_back(mp(p, x)); sum += dis(x, p); for(int i = 0; i < n; i ++) { if(!vis[i]) { pq.push(mp(-dis(i, x), mp(i, x))); } } } double ans = 0; for(int filter = 0; filter < nedge.size(); filter ++) { int i = nedge[filter].fi; int j = nedge[filter].nd; int a = bfs(i, j); int b = bfs(j, i); ans = max(ans, (a + b) / (sum - dis(i, j))); } printf("%.2lf\n", ans); } return 0; }