题目:
http://poj.org/problem?id=2728
题解:
二分比率,然后每条边边权变成w-mid*dis,用prim跑最小生成树就行
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define N 1005 using namespace std; int n,tot; double x[N],y[N],z[N],dis[N]; bool vis[N]; double mul(double x) {return x*x;} double dist(int a,int b) { return sqrt(mul(x[a]-x[b])+mul(y[a]-y[b])); } bool check(double mid) { memset(vis,0,sizeof(vis)); for (int i=2;i<=n;i++) dis[i]=fabs(z[1]-z[i])-mid*dist(1,i); vis[1]=1; int tot=n-1; int id=-1; double val=0.0,tmp=0.0; while(tot--) { id=-1; for (int i=1;i<=n;i++) { if(!vis[i]) { if(id==-1) id=i; else if(dis[id]>dis[i]) id=i; } } tmp+=dis[id]; vis[id]=1; for (int i=1;i<=n;i++) { if(!vis[i]) { dis[i]=min(dis[i],fabs(z[i]-z[id])-mid*dist(i,id)); } } } return tmp<=0.0; } int main() { while (scanf("%d",&n)!=EOF) { if (!n) break; for (int i=1;i<=n;i++) scanf("%lf%lf%lf",&x[i],&y[i],&z[i]); double l=0.0,r=0.0,mid; for (int i=2;i<=n;i++) r+=fabs(z[i]-z[1]); for(int i=1;i<=50;i++) { mid=(l+r)/2.0; if (check(mid)) r=mid; else l=mid; } printf("%.3lf\n",r); } return 0; }