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 }
康复训练中~欢迎交流!