uvalive 5731 Qin Shi Huang’s National Road System

题意:

秦始皇要修路使得所有的城市连起来,并且花费最少;有一个人,叫徐福,他可以修一条魔法路,不花费任何的钱与劳动力。

秦始皇想让修路的费用最少,但是徐福想要受益的人最多,所以他们经过协商,决定让 A / B 最大,A代表被魔法路连接的两个城市的人口总数,B代表修的路中非魔法路的总长度。

输出 A / B 的最大值。

思路:

A / B 最大,则A尽可能大,B尽可能小,所以首先把MST求出来。由于每个城市的人口有很大的偏差,所以必须枚举每一条边,计算连接的两个城市的人口,复杂度为O(n^2),所以每次替换边的复杂度必须是O(1)。

由于是稠密图,所以用prim算法,prim算法在O(n^2)的复杂度的时候,可以维护最小生成树上两点之间的最长边,这样就可以在过程中把两点间的最长边保存下来。这个是依靠已知的前驱节点实现的。复杂度为O(n^2)。

枚举每一条边时,如果这条边是MST中的边,那么就直接计算 A / B;如果这条边不在MST中,加入这条边就会成环,这时我们保存的信息就起作用了,成环之后把在MST中的连接这两点的最长边去掉,就是新的生成树的权值,且保证了B尽可能小。替换的时间复杂度为O(1)。

代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <math.h>
  6 using namespace std;
  7 const int maxn = 1005;
  8 double path[maxn][maxn];
  9 double g[maxn][maxn];
 10 double dis[maxn];
 11 bool vis[maxn];
 12 bool used[maxn][maxn];
 13 int peo[maxn];
 14 int pre[maxn];
 15 double ans;
 16 struct point
 17 {
 18     int x,y;
 19 }p[maxn];
 20
 21 double cal(int i,int j)
 22 {
 23     double x2 = (p[i].x - p[j].x) * (p[i].x - p[j].x);
 24     double y2 = (p[i].y - p[j].y) * (p[i].y - p[j].y);
 25
 26     return sqrt(x2 + y2);
 27 }
 28
 29 int prim(int n)
 30 {
 31     memset(vis,0,sizeof(vis));
 32     memset(path,0,sizeof(path));
 33     memset(used,0,sizeof(used));
 34     for (int i = 0;i <= n;i++) dis[i] = 1e15;
 35
 36     vis[1] = 1;
 37     dis[1] = 0;
 38
 39     int tot = 0;
 40     ans = 0;
 41     //double len = 0;
 42
 43     for (int i = 2;i <= n;i++)
 44     {
 45         pre[i] = 1;
 46         dis[i] = g[1][i];
 47     }
 48
 49     for (int i = 1;i < n;i++)
 50     {
 51         int u;
 52         double d = 1e15;
 53
 54         for (int j = 1;j <= n;j++)
 55         {
 56             if (!vis[j] && dis[j] < d)
 57             {
 58                 d = dis[j];
 59                 u = j;
 60             }
 61         }
 62
 63         vis[u] = 1;
 64
 65         ans += d;
 66
 67         //tot = max(peo[u] + peo[pre[u]],tot);
 68
 69         used[u][pre[u]] = used[pre[u]][u] = 1;
 70
 71         for (int j = 1;j <= n;j++)
 72         {
 73             if (vis[j] && j != u)
 74                 path[u][j] = path[j][u] = max(d,path[j][pre[u]]);
 75         }
 76
 77         for (int j = 1;j <= n;j++)
 78         {
 79             if (!vis[j])
 80             {
 81                 if (g[u][j] < dis[j])
 82                 {
 83                     dis[j] = g[u][j];
 84                     pre[j] = u;
 85                 }
 86             }
 87         }
 88     }
 89
 90     //printf("%.2f **\n",ans);
 91
 92     return tot;
 93 }
 94
 95 int main()
 96 {
 97     int t;
 98
 99     scanf("%d",&t);
100
101     while (t--)
102     {
103         int n;
104
105         scanf("%d",&n);
106
107         for (int i = 1;i <= n;i++)
108         {
109             scanf("%d%d%d",&p[i].x,&p[i].y,&peo[i]);
110         }
111
112         for (int i = 1;i <= n;i++)
113         {
114             for (int j = 1;j <= n;j++)
115             {
116                 g[i][j] = 1e15;
117             }
118         }
119
120         for (int i = 1;i <= n;i++)
121         {
122             for (int j = i+1;j <= n;j++)
123             {
124                 g[i][j] = g[j][i] = cal(i,j);
125             }
126         }
127
128         prim(n);
129
130         double ans1 = 0;
131
132         for (int i = 1;i <= n;i++)
133         {
134             for (int j = i + 1;j <= n;j++)
135             {
136                 if (used[i][j])
137                 {
138                     int peop = peo[i] + peo[j];
139                     ans1 = max(peop / (ans - g[i][j]),ans1);
140
141                     //printf("%d %d %d %.2f **\n",i,j,peop,ans - g[i][j]);
142                 }
143                 else
144                 {
145                     int peop = peo[i] + peo[j];
146                     ans1 = max(peop / (ans - path[i][j]),ans1);
147                     //printf("%d %d %d %.2f **\n",i,j,peop,ans - path[i][j]);
148                 }
149             }
150         }
151
152         printf("%.2f\n",ans1);
153
154         //printf("%.2f",path[1][4]);
155     }
156
157     return 0;
158 }

原文地址:https://www.cnblogs.com/kickit/p/8809028.html

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

uvalive 5731 Qin Shi Huang’s National Road System的相关文章

UVALive 5713 Qin Shi Huang&#39;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需要

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

UVA - 1494 Qin 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