链接:点击打开链接
题意:给一个完全图,每个点有一个权值,求一棵生成树,你可以使其中一条边的权值变成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; }