书P368
题目地址:https://ac.nowcoder.com/acm/contest/1056/C
① 0/1分数规划https://blog.nowcoder.net/n/70ad985a57bc4085aaee4d40fd2a9451
② Prim算法https://blog.nowcoder.net/n/012b92baab1f4ee59bb17b9bcb8dadb4
#include<bits/stdc++.h> using namespace std; const double inf=1e18; const int N=15e4+10; const int maxn=1e3+10; const double eps=1e-5; int n; double cost[maxn][maxn],dis[maxn][maxn],x[maxn],y[maxn],z[maxn]; int vis[maxn]; double get_dis(int a,int b) { return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));//求两点间距离 } int check(double x)//Prim算法求最大生成树边权之和是否非负 { memset(vis,0,sizeof(vis)); double sum=0,lowcost[maxn]; for(int i=1;i<=n;i++) { lowcost[i]=cost[1][i]-x*dis[1][i]; } for(int i=2;i<=n;i++) { double temp=inf; int k=-1; for(int j=2;j<=n;j++) { if(!vis[j]&&lowcost[j]<temp) { k=j; temp=lowcost[j]; } } if(k==-1) { break; } vis[k]=1; sum+=temp; for(int j=2;j<=n;j++) { if(!vis[j]&&cost[k][j]-x*dis[k][j]<lowcost[j]) { lowcost[j]=cost[k][j]-x*dis[k][j]; } } } if(sum>=0)return 1; return 0; } int main() { while(cin>>n&&n!=0) { for(int i=1;i<=n;i++) { cin>>x[i]>>y[i]>>z[i]; } for(int i=1;i<=n-1;i++) { for(int j=i+1;j<=n;j++) { dis[i][j]=dis[j][i]=get_dis(i,j);//转化为无向图中的收益与代价 cost[i][j]=cost[j][i]=abs(z[i]-z[j]); } } double l=0.0,r=100.0; while(r-l>=eps) { double mid=(l+r)/2; if(check(mid))//判断mid比答案大还是小 { l=mid; } else { r=mid; } } printf("%.3f\n",r); } return 0; }