本题的题意是某一条路可以不用花钱,这条路所连接的两个城市权值之和为A,然后求出最小生成树所需要的代价B,求出最大的A/B
思路很清楚,因为有了这条路之后这两个点已经连通了,其他的线段肯定是最小生成树的线段(因为所需要花费的代价少于最小生成树的代价)。我们可以先将最小生成树的线段列举出来,然后将某一条边去掉,这样B的值确定,然后确定A的值,即找两个集合各自最大的节点值。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 1005
using namespace std;
int G[N];
double ans,answer,top;
struct node
{
int t,x,y;
int w;
}Node[N];
struct flow
{
int x;int y;
double len;
}Flow[N*500],flow1[N];
int findx(int x)
{
return G[x]==x?x:G[x]=findx(G[x]);
}
double f(int i,int j)
{
double p=(Node[i].x-Node[j].x)*(Node[i].x-Node[j].x);
double q=(Node[i].y-Node[j].y)*(Node[i].y-Node[j].y);
return sqrt(p+q);
}
bool cmp(flow a,flow b)
{
return a.len<b.len;
}
bool compare(node a,node b)
{
return a.w>b.w;
}
int main()
{
int T,n,i,j,r;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d %d %d",&Node[i].x,&Node[i].y,&Node[i].w);
Node[i].t=i;
G[i]=i;
}
int t=0;
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
{
Flow[t].x=i;
Flow[t].y=j;
Flow[t].len=f(i,j);
t++;
}
sort(Flow,Flow+t,cmp);
ans=0,r=0,top=0;
for(i=0;i<t;i++)
{
int p=findx(Flow[i].x);
int q=findx(Flow[i].y);
if(p!=q)
{
flow1[r].x=Flow[i].x;
flow1[r].y=Flow[i].y;
flow1[r].len=Flow[i].len;
r++;
ans+=Flow[i].len;
G[p]=q;
}
}
sort(Node,Node+n,compare);
for(i=0;i<r;i++)
{
ans-=flow1[i].len;
for(j=0;j<n;j++) G[j]=j;
for(j=0;j<r;j++)
{
if(j==i) continue;
int p=findx(flow1[j].x);
int q=findx(flow1[j].y);
if(p!=q)
{
G[p]=q;
}
}
for(j=1;j<n;j++)
{
if(findx(Node[j].t)!=findx(Node[0].t))
{
answer=(double)(Node[0].w+Node[j].w)/ans;
if(top<answer) top=answer;
break;
}
}
ans+=flow1[i].len;
}
printf("%.2f\n",top);
}
return 0;
}