【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
",l);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/13597202.html