【题意】:给出n(n<=1000)个城市的坐标和城市的居住人口,要求修n-1条路使得n个城市连通,修路的代价就是路长,并且允许免费修一条路。问:被免费的路所连接的两个城市人口之和比上修路的代价(这里是n-2条路的代价之和,因为有一条路是免费的)的最大值是多少。

【题解】:这题是北京现场赛的A题,当时想到解法,可惜是O(n*n*n)的。
               其实这题就是一道次小生成树变形,不过当时不会,现在学了,顺便切了它。
               首先可以想到最小生成树,但是免费的路这个怎么处理,考虑到数据n<=1000,我们可以枚举两点之间的路。
               如果该路已经在MST上,那么比值就是(cnt[u]+cnt[v]) / (MST - w(u, v));
               如果该路不在MST上,那么我们把这条路加上去的话肯定会形成一个环,为了保证比值最大,我们显然要删除环上第二大的边(第一大的边肯定是新添加的这条路,不能删除),那么比值就是(cnt[u]+cnt[v]) / (MST - path[u][v]),其中path[i][j]表示在MST上节点i到节点j路径上的最大边。
               复杂度O(n*n)。

【代码】:
 1 #include "iostream"
 2 #include "cstdio"
 3 #include "cstring"
 4 #include "algorithm"
 5 #include "vector"
 6 #include "queue"
 7 #include "cmath"
 8 #include "string"
 9 #include "cctype"
10 using namespace std;
11 #define pb push_back
12 #define lc(x) (x << 1)
13 #define rc(x) (x << 1 | 1)
14 #define lowbit(x) (x & (-x))
15 #define ll long long
16 #define maxn 1005
17 const double dinf = 1e10;
18 const int inf = 1 << 30;
19 int n, m;
20 int pre[maxn], stack[2*maxn], top;
21 double maz[maxn][maxn], dist[maxn], path[maxn][maxn];
22 bool visit[maxn];
23 struct Point {
24     double x, y;
25     int cnt;
26 }p[maxn];
27 
28 double getdist(const Point &a, const Point &b) {
29     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
30 }
31 
32 double prim(int s) {
33     double ans = 0;
34     for(int i = 0; i < n; i++) visit[i] = false, dist[i] = dinf, pre[i] = s;
35     dist[s] = 0, top = 0;
36     while(1) {
37         int u = -1;
38         for(int i = 0; i < n; i++) {
39             if(!visit[i] && (u == -1 || dist[i] < dist[u])) u = i;
40         }
41         if(u == -1) break;
42         stack[top++] = u, visit[u] = true;
43         ans += dist[u];
44         for(int i = 0; i < top; i++) {
45             if(stack[i] == u) continue;
46             path[stack[i]][u] = max(path[stack[i]][pre[u]], dist[u]);
47             path[u][stack[i]] = path[stack[i]][u];
48         }
49         for(int i = 0; i < n; i++) {
50             if(!visit[i] && maz[u][i] < dist[i]) 
51                 dist[i] = maz[u][i], pre[i] = u;
52         }
53     }
54     return ans;
55 }
56 
57 void solve() {
58     double MST = prim(0), ans = 0.0;
59     for(int i = 0; i < n; i++) {
60         for(int j = 0; j < n; j++) {
61             if(i == j) continue;
62             if((pre[i] == j || pre[j] == i)) ans = max(ans, (p[i].cnt + p[j].cnt) / (MST - maz[i][j]));
63             else ans = max(ans, (p[i].cnt + p[j].cnt) / (MST - path[i][j]));
64         }
65     }
66     printf("%.2f\n", ans);
67 }
68 
69 int main() {
70     int T;
71     scanf("%d", &T);
72     while(T--) {
73         scanf("%d", &n);
74         for(int i = 0; i < n; i++) {
75             scanf("%lf%lf%d", &p[i].x, &p[i].y, &p[i].cnt);
76         }
77         for(int i = 0; i < n; i++) {
78             for(int j = 0; j < n; j++) {
79                 maz[i][j] = getdist(p[i], p[j]);
80                 path[i][j] = 0.0;
81             }
82         }
83         solve();
84     }
85     return 0;
86 }