这题和求次小生成树的思路有点像。
首先求出最小生成树,在此过程中,我们用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;
}