链接:点击打开链接
题意:给一个完全图,每个点有一个权值,求一棵生成树,你可以使其中一条边的权值变成0,求该边两点的权值和除以生成树的边权和的最小值
代码:
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const double INF=0x3f3f3f3f;
using namespace std;
double dis[1005],path[1005][1005],G[1005][1005];
int n,x[1005],y[1005],p[1005],pre[1005],vis[1005],used[1005][1005];
double prim(int v){
int i,j,u;
double sum,tmp;
sum=0;
memset(vis,0,sizeof(vis));
memset(used,0,sizeof(used));
memset(path,0,sizeof(path));
for(i=1;i<=n;i++){
dis[i]=G[v][i];
pre[i]=1;
}
vis[v]=1;
for(i=1;i<n;i++){
u=v;
tmp=INF;
for(j=1;j<=n;j++)
if(dis[j]<tmp&&vis[j]==0){
tmp=dis[j];
u=j;
}
sum+=tmp;
vis[u]=1;
used[u][pre[u]]=used[pre[u]][u]=1;
for(j=1;j<=n;j++){
if(vis[j]&&j!=u) //求环上的最大值,pre为父节点
path[u][j]=path[j][u]=max(path[j][pre[u]],dis[u]);
if(!vis[j]){
if(dis[j]>G[u][j]){
dis[j]=G[u][j];
pre[j]=u;
}
}
}
}
return sum;
}
int main(){ //因为A的有N*N种可能,因此我们可以使B尽量小
int i,j,t; //最小生成树去掉一条边后剩的边的权值的和依旧
double ans,tmp; //是最小的,每去掉一条边后,一棵树被分成了两
scanf("%d",&t); //棵树,A/B的最大值也就是A中点权最大的和B中点
while(t--){ //权最大的
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d%d%d",&x[i],&y[i],&p[i]);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) //有N*N条边因此不用初始化
G[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
tmp=prim(1);
ans=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j){
if(used[i][j]) //如果在最小生成树上则直接删除
ans=max(ans,(p[i]+p[j])*1.0/(tmp-G[i][j]));
else //否则则删除当前环的最大值
ans=max(ans,(p[i]+p[j])*1.0/(tmp-path[i][j]));
}
printf("%.2lf\n",ans);
}
return 0;
}