测试地址:Desert King
题目大意:平面上有
做法:本题可以转化成最优比率生成树来解决。
求费用和与管道总长的最小比值,就是求管道总长与费用和的最大比值的倒数,这样就可以把问题转化为0-1分数规划中的一个经典问题——最优比率生成树来解决了,具体做法网上有比我讲得好的,这里就不赘述了,注意一下费用和为0的情况即可。本人这里用的是二分+最大生成树的做法写的,时间复杂度为
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define eps 1e-6
using namespace std;
int n;
double x[1010],y[1010],h[1010],dis[1010];
bool vis[1010];
double d(int i,int j)
{
return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
bool check(double l)
{
double z=0.0;
memset(vis,0,sizeof(vis));
vis[1]=1,dis[1]=0;
for(int i=2;i<=n;i++)
dis[i]=d(1,i)-l*fabs(h[1]-h[i]);
for(int i=1;i<n;i++)
{
double mx=-200000000;
mx*=10000.0;
int mni;
for(int j=1;j<=n;j++)
if (!vis[j]&&dis[j]>mx) mx=dis[j],mni=j;
vis[mni]=1;
z+=dis[mni];
for(int j=1;j<=n;j++)
if (!vis[j]) dis[j]=max(dis[j],d(mni,j)-l*fabs(h[mni]-h[j]));
}
if (z<0) return 0;
else return 1;
}
int main()
{
while(scanf("%d",&n)&&n)
{
bool flag=0;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf",&x[i],&y[i],&h[i]);
for(int j=1;j<i;j++) if (h[i]!=h[j]) {flag=1;break;}
}
if (!flag) {printf("0.000
");continue;}
double l=0,r=200000000;
while(r-l>=eps)
{
double mid=(l+r)/2;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.3f
",1.0/r);
}
return 0;
}