2011 Asia Beijing Regional Contest
题目大意:有N个城市,秦始皇要用N-1条路将他们全部连起来,秦始皇希望这N-1条路长度
之和最短。这时候,徐福跳出来说他有魔法,可以凭空变出其中任意一条路来。
秦始皇希望徐福将N-1条路中最长的那条路变出来,但是徐福希望把修路要求人数最多的那条
路变出来(每条路修路的人力是两座城市的人口和)。最终,秦始皇给出了一个公式 A/B
徐福变出的那条路所需人力/除了这条路之外的N-2条路的和 最大。
简化大意为:给你N个城市的坐标(x,y)和人口。 得到他的最小生成树之后,去掉最小生成树上
的一条边,使得这条路两边连接城市的人数和/最小生成树上其他N-2条路的长度和(A/B)最大。
输出这个最大的比值。
思路:为了使得上述公式A/B比值最大,就需要B尽可能小。
先求出最小生成树MST,再选择要删去哪一条边,可以遍历MST上的边,假设枚举的边长度为
Len[i][j],最终结果就为max(A/MST-Len[i][j])(1<=i<=n,i+1<=j<=n)。其中A为最小生成树
上的边。若A不是最小生成树上的边。最小生成树加上A边就会成为一个环。为了使得他原先为
一个生成树,就要删去这个环上除了A边外权值最大的边,就是原先最小生成树中权值最大的边。
最终结果还是max(A/MST-Len[i][j])(1<=i<=n,i+1<=j<=n)。而加上A边所形成的生成树其实
就是次小生成树。所以问题就转换为求次小生成树,再遍历求结果。
注意:代码用C++提交就超时,G++提交就AC。不知道什么情况。。。按理说C++比G++高效
才对。不知道是什么原因~求大神给解释解释哈~感激不尽。
参考博文:http://tech.ddvip.com/2013-10/1380576235203623.html
#include<algorithm> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int MAXN = 1010; const int MAXM = 1000010; int father[MAXN]; int find(int x) { if(x != father[x]) father[x] = find(father[x]); return father[x]; } struct Node { int from; int to; double w; }; Node Edges[MAXM]; bool cmp(Node a,Node b) { return a.w < b.w; } struct Node1 { int to; int next; }; Node1 Vertex[MAXN]; struct Node2 { int x; int y; double d; }; Node2 Point[MAXN]; double Dist(int i,int j) { double x = Point[i].x - Point[j].x; double y = Point[i].y - Point[j].y; return sqrt(x*x+y*y); } int N,M,Head[MAXN],End[MAXN]; double Len[MAXN][MAXN]; double Kruskal() { int i,x,y,w,v,k = 0; double ans = 0; for(i = 1; i <= N; ++i) { Vertex[i].to = i; Vertex[i].next = -1; Head[i] = End[i] = i; } for(i = 0; i < M; ++i) { if(k == N-1) break; if(Edges[i].w < 0) continue; x = find(Edges[i].from); y = find(Edges[i].to); if(x != y) { for(w = Head[x]; w != -1; w = Vertex[w].next) { for(v = Head[y]; v != -1; v = Vertex[v].next) { Len[Vertex[w].to][Vertex[v].to] = Len[Vertex[v].to][Vertex[w].to] = Edges[i].w; } } father[y] = x;//改为father[x] = y就错 Vertex[End[y]].next = Head[x]; Head[x] = Head[y]; k++; ans += Edges[i].w; if(k == N-1) break; } } return ans; } double maxv(double a,double b) { return a > b ? a : b; } int main() { int T,i,j; scanf("%d",&T); while(T--) { scanf("%d",&N); for(i = 1; i <= N; ++i) father[i] = i; for(i = 1; i <= N; ++i) { scanf("%d%d%lf",&Point[i].x,&Point[i].y,&Point[i].d); } M = 0; for(i = 1; i <= N; ++i) { for(j = i+1; j <= N; ++j) { Edges[M].from = i; Edges[M].to = j; Edges[M++].w = Dist(i,j); } } sort(Edges,Edges+M,cmp); double MST = Kruskal(); double ans = 0; for(i = 1; i <= N; ++i) { for(j = i+1; j <= N; ++j) ans = maxv(ans,(Point[i].d + Point[j].d)/(MST-Len[i][j])); } printf("%.2lf\n",ans); } return 0; }
HDU4081 Qin Shi Huang's National Road System【Kruska】【次小生成树】
原文:http://blog.csdn.net/lianai911/article/details/42218969