http://acm.hdu.edu.cn/showproblem.php?pid=4081
题意为秦始皇需要建立一个n-1条路来连接n个城市,在这n-1条边中可以无消耗建立一条边,满足(该边连接的城市人口和/其他n-2条边距离和)最大,且其他n-2条边的距离尽可能小
首先算出该图的最小生成树mst,对于这条特殊的边,枚举每条边,若该边在最小生成树里,答案即是人口/mst-该边权值;若不在mst中,将其加入mst后删掉环中最长边(即求次小生成树),即是人口/mst-最长边。
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
using namespace std;
const int maxn = 1004;
struct node {
int x, y, p;
} a[maxn];
int t, n, vis[maxn], pre[maxn], used[maxn][maxn];
double dis[maxn][maxn], f[maxn][maxn], dist[maxn], mst = 0;
void prim() {
mst = 0;
memset(vis, 0, sizeof(vis));
memset(used, 0, sizeof(used));
memset(f, 0, sizeof(f));
vis[1] = 1;
for(int i = 2; i <= n; i++) dist[i] = dis[1][i], pre[i] = 1;
for(int i = 1; i < n; i++) {
double tmp = 0x3f3f3f3f * 1.0;
int to;
for(int j = 1; j <= n; j++) if(!vis[j]) {
if(tmp > dist[j]) {
tmp = dist[j];
to = j;
}
}
vis[to] = 1;
mst += tmp;
used[pre[to]][to] = used[to][pre[to]] = 1;
for(int j = 1; j <= n; j++) {
if(vis[j] && j != to) f[to][j] = f[j][to] = max(f[pre[to]][j], tmp);
if(!vis[j]) {
if(dist[j] > dis[to][j]) {
pre[j] = to;
dist[j] = dis[to][j];
}
}
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(2);
cout << fixed;
cin >> t;
while(t--) {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i].x >> a[i].y >> a[i].p;
for(int j = 1; j < i; j++) {
dis[i][j] = dis[j][i] = sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}
}
prim();
double ans = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j < i; j++) {
if(used[i][j]) ans = max(ans, (a[i].p + a[j].p) / (mst - dis[i][j]));
else ans = max(ans, (a[i].p + a[j].p) / (mst - f[i][j]));
}
}
cout << ans << endl;
}
}