【POJ2728】沙漠王国Desert King-最优比率生成树-01分数规划
Description
大卫刚被选举为沙漠王国的国王。为了赢得人们的尊重,他决定修建渠道,把水引到整个国家的每个村庄。使得连接到中心村庄的所有村庄都将会被灌溉。经过多天的研究,他最终制定出目的。就是使建造渠道每英里的平均价格最小。换句话说,建造渠道的总体成本与总长度的比值必须最小。只需要建立必须的渠道,把水引到所有的村庄即可。也就是每个村庄仅一种方式连接到中心村庄。
已知每个村庄的位置和高度,任意两个村庄之间的渠道必须是直的。长度为这两个村庄(x1,y1)和(x2,y2)之间的距离sqrt((x1-x2)2+(y1-y2)2),建立渠道的花费为这两个村庄高度差的绝对值。每个村庄都在不同高度,注意水能够通过特殊的设备从低处流到高处(不考虑设备费用),没有任意三个村庄位于同一条水平线上。现在国王想知道建造渠道每英里的平均价格最小是多少?
Input
输入有多组测试数据;
每组测试数据第一行包含一个整数N(2<=N<=1000),表示村庄的个数。
接下来n行,每行三个整数x,y和z(0<=x,y<10000,0<=z<10000000),表示一个村庄位于(x,y)这点,高度为z,文件最后一行以一个0作为结束,不用处理。
Output
对于每组测试数据,输出一行为建造渠道的总体成本与总长度的比值,保留三位小数。
Sample Input
4
0 0 0
0 1 1
1 1 2
1 0 3
0
Sample Output
1.000
思路
- 最优比率生成树(01分数规划运用实例)
- 完全图用prim
- 标准上界应该为high之和/min(dis),但1e5也能过
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
int n,flag[1005];
double dis[1005][1005],high[1005][1005],d[1005];
struct fdfdfd{double x,y,z;}e[1005];
double js(int i,int j){return sqrt((e[i].x-e[j].x)*(e[i].x-e[j].x)+(e[i].y-e[j].y)*(e[i].y-e[j].y));}
bool prim(double x)
{
double sum=0;
memset(flag,0,sizeof(flag));
memset(d,0x7f,sizeof(d)); d[1]=0;
for(int i=1;i<=n;++i)
{
double minn=0x7fffffff; int k=-1;
for(int j=1;j<=n;++j)
if(!flag[j]&&d[j]<minn) minn=d[j],k=j;
flag[k]=1; sum+=d[k];
for(int j=1;j<=n;++j)
if(!flag[j]) d[j]=min(d[j],high[k][j]-x*dis[k][j]);
}
return (sum>0);
}
int main()
{
while(scanf("%d",&n))
{
if(!n) break;
for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&e[i].x,&e[i].y,&e[i].z);
for(int i=1;i<=n;++i)
for(int j=i+1;j<=n;++j)
{
dis[i][j]=dis[j][i]=js(i,j);
high[i][j]=high[j][i]=fabs(e[i].z-e[j].z);
}
double l=0,r=100000;
while(r-l>1e-8)
{
double mid=(r+l)/2.0;
if(prim(mid)) l=mid;
else r=mid;
}
printf("%.3f\n",l);
}
return 0;
}