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 **
",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 **
",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 **
",i,j,peop,ans - path[i][j]);
148                 }
149             }
150         }
151         
152         printf("%.2f
",ans1);
153         
154         //printf("%.2f",path[1][4]);
155     }
156     
157     return 0;
158 }
原文地址:https://www.cnblogs.com/kickit/p/8809028.html