这题和求次小生成树的思路有点像。
首先求出最小生成树,在此过程中,我们用maxcost[a][b]维护在MST中a,b之间的最大边权值。
状态转移方程: maxcost[a][b] = max(maxcost[pre[a]][b] , dis[a]) pre[a]是a的前驱节点,dis[a]是到a的最短路。
然后我们在再枚举每一条边,每次用当前枚举的边置换maxcost[a][b],然后计算并更新结果。
#include <iostream> #include<cmath> #include<stdio.h> #include<cstring> #define maxn 1010 #define INF 10000000 using namespace std; int t,n,cnt; struct Node{ double x,y; int peo; }; Node node[maxn]; struct Edge{ int from,to,next,mst; double dist; }; Edge e[maxn * maxn]; int head[maxn]; int vis[maxn]; int mst[maxn][maxn]; double ans,result; double maxcost[maxn][maxn]; double dis[maxn]; int pre[maxn]; double mini; void add_edge(int a,int b) { double tmp = sqrt((node[a].x - node[b].x)*(node[a].x - node[b].x) + (node[a].y - node[b].y)*(node[a].y - node[b].y)); e[cnt].from = a; e[cnt].to = b; e[cnt].dist = tmp; e[cnt].next = head[a]; head[a] = cnt; cnt++; } void init() { cnt = 0; ans = 0; result = 0; memset(head,-1,sizeof head); memset(mst,0,sizeof mst); memset(maxcost,0,sizeof maxcost); } bool prim() { int k; memset(vis,0,sizeof vis); for(int i = 1;i <= n;i++) dis[i] = INF; for(int i = head[1];i != -1;i = e[i].next) { int cur = e[i].to; dis[cur] = min(e[i].dist,dis[cur]); pre[cur] = 1; } vis[1] = 1; dis[1] = 0; for(int j = 1;j < n;j++) { mini = INF; for(int i = 1;i <= n;i++) { if(!vis[i] && dis[i] < mini) { mini = dis[i]; k = i; } } if(mini == INF) return false; vis[k] = 1; mst[pre[k]][k] = 1; ans+=dis[k]; for(int i = head[k];i !=-1;i=e[i].next) { int cur = e[i].to; maxcost[k][cur] = maxcost[cur][k] = max(maxcost[pre[k]][cur],dis[k]); if(!vis[cur] && e[i].dist < dis[cur]) { pre[cur] = k; dis[cur] = e[i].dist; } } } return true; } void work() { for(int i = 1;i <= n;i++) { for(int j = head[i];j !=-1;j = e[j].next) { int from = i; int to = e[j].to; double tmp = maxcost[from][to]; tmp =ans - tmp; double tmp1 = node[from].peo + node[to].peo; tmp1/=tmp; if(tmp1 > result) result = tmp1; } } } int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); init(); for(int i = 1;i <= n;i++) { scanf("%lf %lf %d",&node[i].x,&node[i].y,&node[i].peo); } for(int i = 1;i <= n;i++) for(int j = i + 1;j <= n;j++) { add_edge(i,j); add_edge(j,i); } prim(); work(); printf("%.2lf\n",result); } return 0; }