UVALive 5713 Qin Shi Huang's National Road System秦始皇修路(MST,最小瓶颈路)

题意:

  秦始皇要在n个城市之间修路,而徐福声可以用法术位秦始皇免费修1条路,每个城市还有人口数,现要求徐福声所修之路的两城市的人口数之和A尽量大,而使n个城市互通需要修的路长B尽量短,从而使得A/B最大。问A/B最大是多少?(1000个城市)

思路:

  老徐可免费修得1条路,那么剩下最多也只需要修n-2条路了,这n-2条路要尽量挑短的,而老徐的那条无所谓长短,只要两城人口尽量多即可。这是没有什么贪心策略的,因为老徐所修之路会影响MST的权值之和的大小。穷举所有城市对要O(n*n),再求次MST需要O(n*n),不可行。

  换个思路,如果能先求得MST,然后穷举要老徐所要修的路,那么在加上老徐的路之后,必然会有个环的出现,这个环中有一条边是不需要的,当然不是老徐那条。这只需要在原MST中求这个环的最小瓶颈路就行了,将其删掉,加上老徐的路,构成新的MST了,进行求值。穷举老徐所要修的路也要O(n*n),那么求瓶颈路就只能用O(1)了。这可以预处理出任意城市对之间的最小瓶颈路,O(n*n)而已。

  任意点对的最小瓶颈路的求法:对原图求最小生成树,只留下树边,树中任意点对之间的路径就是该点对的最小瓶颈路。接着对树图进行DFS,在DFS过程中,顺便求出任意点对的最小瓶颈路,考虑求当前节点x到其他点的最小瓶颈路,设其父亲far,那么x可以通过far到达前面已经访问过的节点,为maxcost[已访问过的节点][far]与cost[far][x]其中的大者。按此思路,在DFS过程中可以求出任意点对的最小瓶颈路。

  1 #include <bits/stdc++.h>
  2 #include <cstdio>
  3 #include <vector>
  4 #include <iostream>
  5 #include <algorithm>
  6 #define INF 0x7f7f7f7f
  7 #define pii pair<int,int>
  8 #define LL long long
  9 using namespace std;
 10 const int N=1001000;
 11 int a[N], b[N], seq[N];     //求MST用的
 12 int x[N], y[N], p[N];       //所给的坐标及人口数
 13 int pre[N], vis[N], used[N];    //求任意点对最小瓶颈路用的
 14 double w[N], maxcost[1001][1001]; //两点间的最小瓶颈maxcost
 15 vector<int>  vect[N];    //建树时用
 16 vector<int> dfn;         //记录访问过的节点
 17
 18 int cmp(int a,int b){return w[a]<w[b];}
 19 int find(int x){return pre[x]==x? x: pre[x]=find(pre[x]);}  //并查集
 20 double dis(int a,int b){return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));}
 21
 22
 23
 24
 25 void DFS(int x)
 26 {
 27     dfn.push_back(x);   //访问过
 28     vis[x]=1;
 29     for(int i=0; i<vect[x].size(); i++)
 30     {
 31         int t=vect[x][i];
 32         if(!vis[t] )
 33         {
 34             for(int j=0; j<dfn.size(); j++) //对于所有已经访问过的节点
 35             {
 36                 int from=dfn[j];
 37                 maxcost[t][from]=maxcost[from][t]=max(maxcost[from][x], dis(x, t) );//通过x连到t
 38             }
 39             DFS(t);
 40         }
 41     }
 42 }
 43
 44 void init(int n)    //一堆初始化。
 45 {
 46     dfn.clear();
 47     for(int i=1; i<=n; i++) vect[i].clear(),pre[i]=i;
 48     for(int i=1; i<=n; i++)
 49         for(int j=1; j<=n; j++)
 50             maxcost[i][j]=0.0;
 51     memset(used, 0, sizeof(used));
 52     memset(vis,  0, sizeof(vis));
 53 }
 54 double cal(int n, int m)
 55 {
 56     init(n);
 57     double sum=0.0;   //MST
 58     for(int i=0; i<m; i++)      //kruscal求最小生成树
 59     {
 60         int u=find(a[seq[i]]);
 61         int v=find(b[seq[i]]);
 62         if( u!=v )
 63         {
 64             pre[u]=v;               //不是同个连通块,则连接。
 65             vect[a[seq[i]]].push_back( b[seq[i]] ); //顺便建图,方便建树
 66             vect[b[seq[i]]].push_back( a[seq[i]] );
 67             used[seq[i]]=1;
 68             sum+=w[seq[i]];
 69         }
 70     }
 71
 72     DFS(1);                   //求任意点对间的最小瓶颈路
 73     double ans=0.0;
 74     for(int i=0; i<m; i++)    //穷举徐福声将要建的边。
 75     {
 76         double A=p[a[i]]+p[b[i]], B;
 77
 78         if(used[i])     B=sum-w[i];            //树上的边
 79         else            B=sum-maxcost[a[i]][b[i]];
 80         ans=max( A/B, ans );
 81     }
 82     return ans;
 83 }
 84
 85
 86 int main()
 87 {
 88     freopen("input.txt", "r", stdin);
 89     int t, n;
 90     cin>>t;
 91     while(t--)
 92     {
 93         cin>>n;
 94         for(int i=1; i<=n; i++)    scanf("%d%d%d",&x[i],&y[i],&p[i]);
 95         int cnt=0;
 96         for(int i=1; i<=n; i++)     //求两点间的距离,共n*(n-1)/2条边
 97         {
 98             for(int j=i+1; j<=n; j++)
 99             {
100                 a[cnt]=i;
101                 b[cnt]=j;
102                 w[cnt]=dis(i,j);
103                 seq[cnt]=cnt;   //千万不要用seq[cnt]=cnt++;或者seq[cnt++]=cnt。
104                 cnt++;
105             }
106         }
107         sort(seq, seq+cnt, cmp);        //按边长排序
108         printf("%.2f\n", cal(n, cnt));
109     }
110
111     return 0;
112 }

AC代码

UVALive 5713 Qin Shi Huang's National Road System秦始皇修路(MST,最小瓶颈路)

时间: 2024-08-04 01:06:34

UVALive 5713 Qin Shi Huang's National Road System秦始皇修路(MST,最小瓶颈路)的相关文章

【最小生成树】UVA1494Qin Shi Huang&#39;s National Road System秦始皇修路

Description During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China -- they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally con

uvalive 5731 Qin Shi Huang’s National Road System

题意: 秦始皇要修路使得所有的城市连起来,并且花费最少:有一个人,叫徐福,他可以修一条魔法路,不花费任何的钱与劳动力. 秦始皇想让修路的费用最少,但是徐福想要受益的人最多,所以他们经过协商,决定让 A / B 最大,A代表被魔法路连接的两个城市的人口总数,B代表修的路中非魔法路的总长度. 输出 A / B 的最大值. 思路: A / B 最大,则A尽可能大,B尽可能小,所以首先把MST求出来.由于每个城市的人口有很大的偏差,所以必须枚举每一条边,计算连接的两个城市的人口,复杂度为O(n^2),所

HDU4081 Qin Shi Huang&#39;s National Road System【Kruska】【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3979    Accepted Submission(s): 1372 Problem Description During the Warring States Period of ancient China(4

HDU 4081 Qin Shi Huang&#39;s National Road System 最小生成树

分析:http://www.cnblogs.com/wally/archive/2013/02/04/2892194.html 这个题就是多一个限制,就是求包含每条边的最小生成树,这个求出原始最小生成树然后查询就好了 然后预处理那个数组是O(n^2)的,这样总时间复杂度是O(n^2+m) 这是因为这个题n比较小,如果n大的时候,就需要路径查询了,比如LCA 或者树链剖分达到O(mlogn) #include <iostream> #include <algorithm> #incl

HDU4081 Qin Shi Huang&#39;s National Road System(次小生成树)

枚举作为magic road的边,然后求出A/B. A/B得在大概O(1)的时间复杂度求出,关键是B,B是包含magic road的最小生成树. 这么求得: 先在原图求MST,边总和记为s,顺便求出MST上任意两点路径上的最长边d[i][j]. 当(u,v)是magic road时, 如果它在原本的MST上,则B就等于s-原(u,v)的权,而原(u,v)的权其实就是d[u][v]: 如果它不在原本的MST上,则B就等于s-d[u][v]+0. 总之就是一个式子:B=s-d[u][v]. 于是,在

HDU 4081 Qin Shi Huang&#39;s National Road System

https://vjudge.net/problem/HDU-4081 题意: 秦始皇想要修长城,修成生成树的样子,这是一个大师出现了,他说他可以不耗费人力修出一条路来.他们的目的很不一样,神特么有分歧,最后他们达成了一个协议,假设一个城市的人口为a.那么最后不耗费人力修的那条路所相连的两个城市的人力之和A与修路花费的人力B之比 A/B最大,并且输出最大值. 思路: 枚举去掉每一条边. 首先求出最小生成树,对于最小生成树中的每一条边,如果这条边不花费人力,那么直接计算A和B就可以了. 那么问题是

hdu 4081 Qin Shi Huang&#39;s National Road System(最小生成树+dp)

同样是看别人题解才明白的 题目大意—— 话说秦始皇统一六国之后,打算修路.他要用n-1条路,将n个城市连接起来,并且使这n-1条路的距离之和最短.最小生成树是不是?不对,还有呢.接着,一个自称徐福的游方道士突然出现,他说他可以不消耗任何人力财力,使用法术凭空造一条路,路的长度无所谓,但是只能造一条.那么问题来了,徐福希望将两座人口数最多的城市连接起来,而秦始皇希望将最长的路修好.最后折中了一下, 将A/B最大的一条路用法术修出来.其中A是两座城市的人口和,B是除了用法术修的路以外,其它需要修建的

hdu4081 Qin Shi Huang&#39;s National Road System 次小生成树

先发发牢骚:图论500题上说这题是最小生成树+DFS,网上搜题解也有人这么做.但是其实就是次小生成树.次小生成树完全当模版题.其中有一个小细节没注意,导致我几个小时一直在找错.有了模版要会用模版,然后慢慢融会贯通.我要走的路还长着啊. 讲讲次小生成树的思想吧.首先,在prim算法中做一些改变,求出任意两点(u,v)路径之间的最大权值,并记录,记为maxe[u][v].运行遍prim算法.枚举每一条边,如果该边是属于最小生成树的边,则ratio=(value(u) +value(v) ) /( a

HDU4081 Qin Shi Huang&#39;s National Road System 【次小生成树】

Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3395    Accepted Submission(s): 1189 Problem Description During the Warring States Period of ancient China(4