一、思路:
先求最小生成树T,枚举添加不在T中的边,则添加后一定会形成环。
找到环上边值第二大的边(即环中属于T中的最大边),把它删掉,计算当前生成树的权值,取所有枚举修改的生成树的最小值,即为次小生成树。
二、代码
#include <algorithm> #include <cstdio> #include <cstring> #include <math.h> #include <iostream> using namespace std; #define MAX 0x3f3f3f3f #define N 1010 int n; double dis[N],map[N][N],Max[N][N]; int fa[N],used[N][N],logo[N]; struct Node { int x,y,p; } node[N]; double getdistence(int x1,int y1,int x2,int y2) { double x=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); return x; } double Prim() { double ans = 0; memset(logo, 0, sizeof(logo)); memset(Max, 0, sizeof(Max)); memset(used, 0, sizeof(used)); logo[1] = 1; fa[1] = 0; dis[1] = 0; for (int i = 2; i <= n; i++) { dis[i] = map[1][i]; fa[i] = 1; } for (int i = 1; i < n; i++) { double min1 = MAX; int now = -1; for (int j = 1; j <= n; j++) { if (!logo[j] && min1 > dis[j]) { min1 = dis[j]; now = j; } } if (min1 == MAX) return -1; ans += min1; logo[now] = 1; used[now][fa[now]] = used[fa[now]][now] = 1; for (int j = 1; j <= n; j++) { if (logo[j] && j != now) Max[j][now] = Max[now][j] = max(Max[j][fa[now]], dis[now]); if (!logo[j] && dis[j] > map[now][j]) { dis[j] = map[now][j]; fa[j] = now; } } } return ans; } int main() { int T; scanf("%d",&T); while(T--) { memset(map,0,sizeof(map)); scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].p); for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) map[i][j]=getdistence(node[i].x,node[i].y,node[j].x,node[j].y); double sum=Prim(); double ans=0; for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) { if(i!=j) { if(used[i][j]) ans=max(ans,(node[i].p+node[j].p)*1.0/(sum-map[i][j])); else ans=max(ans,(node[i].p+node[j].p)*1.0/(sum-Max[i][j])); } } printf("%.2lf ",ans); } return 0; }