枚舉每條邊<u, v>, ans=(val[u]+val[v]) / (prim - g[u][v]);
而prim則是包含邊<u, v>的生成樹中最小的那個權值和。
先求出原圖的最小生成樹。use[u][v] = 2時,邊<u, v>在MST上, use[u][v] = 1時,存在邊<u, v>。
f[u][v]表示u->v的最小瓶頸路。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<fstream> #include<sstream> #include<bitset> #include<vector> #include<string> #include<cstdio> #include<cmath> #include<stack> #include<queue> #include<stack> #include<map> #include<set> #define FF(i, a, b) for(int i=a; i<b; i++) #define FD(i, a, b) for(int i=a; i>=b; i--) #define REP(i, n) for(int i=0; i<n; i++) #define CLR(a, b) memset(a, b, sizeof(a)) #define debug puts("**debug**") #define LL long long #define PB push_back using namespace std; const int maxn = 1010; const double INF = 1e10; int n, m, T, use[maxn][maxn]; double g[maxn][maxn], f[maxn][maxn], val[maxn]; double ans1, ans2; double prim() { int pre[maxn] = {-1}; bool vis[maxn] = {0}; double d[maxn], ret = 0; FF(i, 1, n+1) d[i] = INF; d[1] = 0; FF(i, 1, n+1) { int pos; double tmp = INF; FF(j, 1, n+1) if(!vis[j] && d[j] < tmp) tmp = d[j], pos = j; if(pre[pos] != -1) { use[pre[pos]][pos] = use[pos][pre[pos]] = 2; FF(j, 1, n+1) if(vis[j]) f[pos][j] = f[j][pos] = max(f[j][pre[pos]], g[pre[pos]][pos]); } vis[pos] = 1; ret += d[pos]; FF(j, 1, n+1) if(!vis[j] && use[pos][j] && g[pos][j] < d[j]) d[j] = g[pos][j], pre[j] = pos; } return ret; } double Second_MST() { ans1 = prim(); ans2 = -1; FF(i, 1, n+1) FF(j, i+1, n+1) { double A = val[i] + val[j], B; if(use[i][j] == 2) B = ans1 - g[i][j]; else if(use[i][j] == 1) B = ans1 - f[i][j]; ans2 = max(ans2, A/B); } return ans2; } struct Point { double x, y; }p[maxn]; int main() { scanf("%d", &T); while(T--) { scanf("%d", &n); FF(i, 1, n+1) scanf("%lf%lf%lf", &p[i].x, &p[i].y, &val[i]); FF(i, 1, n+1) FF(j, i+1, n+1) { g[i][j] = g[j][i] = sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x) + (p[i].y-p[j].y)*(p[i].y-p[j].y)); use[i][j] = use[j][i] = 1; f[i][j] = f[j][i] = 0; } printf("%.2lf\n", Second_MST()); } return 0; }