[POJ 2728] Desert King
阿新 • • 發佈:2019-02-06
題目描述:
在這麼一個圖中求一棵生成樹,這棵樹的單位長度的花費最小是多少?
題目分析:
最小生成樹的表示式可以這樣寫
∑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;
}