1. 程式人生 > >[POJ 2728] Desert King

[POJ 2728] Desert King

題目描述:

在這麼一個圖中求一棵生成樹,這棵樹的單位長度的花費最小是多少?

題目分析:

最小生成樹的表示式可以這樣寫
∑x[i]*dis[i]-minsum>=0;(x[i]為0或者1,要求為一棵生成樹)

這個題目ans<=(∑cost[i]x[i])/(∑dis[i]*x[i]).變形可得∑x[i](cost[i]-dis[i]*ans)-0>=0;cost[i]-dis[i]*ans就相當於最小生成樹中的dis[i];
二分ans,check的時候跑一邊prime演算法看得到的最小生成樹的和是否>=0,最後可得答案;

題目連結:

AC程式碼:

#include <cstdio>
#include <iostream> #include <cmath> #include <cstring> #define inf 0x3f3f3f3f const int maxm=1120; const double eps=1e-8; struct node{ double x,y,z; }; node a[maxm]; double cost[maxm][maxm],dis[maxm][maxm]; double d[maxm][maxm],low[maxm]; double l,r; int n; bool vis[maxm]; double
distance(node p1,node p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)); } bool check(double mid) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) d[i][j]=d[j][i]=cost[i][j]-mid*dis[i][j]; low[i]=d[1
][i]; } vis[1]=1; double ans=0; for(int i=2;i<=n;i++) { double minn=inf; int id=0; for(int j=1;j<=n;j++) if(!vis[j]&&minn>low[j]) id=j,minn=low[j]; if(minn==inf) break; vis[id]=1,ans+=minn; for(int j=1;j<=n;j++) if(!vis[j]) low[j]=std::min(low[j],d[id][j]); } return ans>=0.0; } int main() { while(scanf("%d",&n),n) { for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].z); l=0,r=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { cost[i][j]=cost[j][i]=std::fabs(a[i].z-a[j].z); dis[i][j]=dis[j][i]=distance(a[i],a[j]); r=std::max(r,cost[i][j]/dis[i][j]); //printf("%.3lf\n",cost[i][j]/dis[i][j]); } //printf("%.3lf\n",r); while(r-l>eps) { double mid=(l+r)/2.0; if(check(mid)) l=mid; else r=mid; } printf("%.3lf\n",l); } return 0; }