【題意】:給出n(n<=1000)個(gè)城市的坐標(biāo)和城市的居住人口,要求修n-1條路使得n個(gè)城市連通,修路的代價(jià)就是路長(zhǎng),并且允許免費(fèi)修一條路。問(wèn):被免費(fèi)的路所連接的兩個(gè)城市人口之和比上修路的代價(jià)(這里是n-2條路的代價(jià)之和,因?yàn)橛幸粭l路是免費(fèi)的)的最大值是多少。

【題解】:這題是北京現(xiàn)場(chǎng)賽的A題,當(dāng)時(shí)想到解法,可惜是O(n*n*n)的。
               其實(shí)這題就是一道次小生成樹變形,不過(guò)當(dāng)時(shí)不會(huì),現(xiàn)在學(xué)了,順便切了它。
               首先可以想到最小生成樹,但是免費(fèi)的路這個(gè)怎么處理,考慮到數(shù)據(jù)n<=1000,我們可以枚舉兩點(diǎn)之間的路。
               如果該路已經(jīng)在MST上,那么比值就是(cnt[u]+cnt[v]) / (MST - w(u, v));
               如果該路不在MST上,那么我們把這條路加上去的話肯定會(huì)形成一個(gè)環(huán),為了保證比值最大,我們顯然要?jiǎng)h除環(huán)上第二大的邊(第一大的邊肯定是新添加的這條路,不能刪除),那么比值就是(cnt[u]+cnt[v]) / (MST - path[u][v]),其中path[i][j]表示在MST上節(jié)點(diǎn)i到節(jié)點(diǎn)j路徑上的最大邊。
               復(fù)雜度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 }