poj2827(最优比率生成树)

链接:http://poj.org/problem?id=2728

题意:有几个点,不同的点有不同坐标和海拔,现在要讲几个点都连成一片,距离为两点之间的欧几里得距离,费用为两点之间的海拔高度,求最小的代价,代价定义为:r=(∑CiXi / ∑DiXi )。

分析:为了使 r 最大, 设计一个子问题---> 让 z = ∑(c[i] * x[i]) - l * ∑(d[i] * x[i]) = ∑(dd[i] * x[i]) 最大 (dd[i] = c[i] - l * d[i]) , 并记为z(l). 我们把z(l)看做以它为边权的最大生成树的总权值.

代码:

#include<cstdio>
#include<math.h>
#include<algorithm>
using namespace std;

const double eps=0.00001;
int n;
const int maxn=1005;
double e[maxn][maxn];
int pre[maxn];
double lowcost[maxn];

struct node{
	int x,y,z;
}p[maxn];

double prime(double x){
	double sum=0;
	double len=0;
	double cost=0;
	for(int i=1;i<=n;i++){
		pre[i]=1;
		lowcost[i]=abs(p[1].z-p[i].z )-x*e[1][i];
	}
	pre[1]=-1;
	for(int i=1;i<=n;i++){
		int u=-1;
		double minn=9999999;
		for(int j=1;j<=n;j++){
			if(pre[j]!=-1&&lowcost[j]<minn){
				minn=lowcost[j];
				u=j;
			}
		}
		if(u!=-1){
			cost+=abs(p[pre[u]].z-p[u].z );
			len+=e[pre[u]][u];
			pre[u]=-1;
			sum+=lowcost[u];
			for(int j=1;j<=n;j++){
				double temp=abs(p[u].z-p[j].z )-x*e[u][j];
				if(pre[j]!=-1&&temp<lowcost[j]){
					lowcost[j]=temp;
					pre[j]=u;
				}
			}
		}
	}
	return sum;
}

double cal(int a,int b){
	return sqrt(1.0 * (p[a].x - p[b].x) * (p[a].x - p[b].x) + 1.0 * (p[a].y - p[b].y) * (p[a].y - p[b].y));
}

int main(){
	while(~scanf("%d",&n),n){
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].z);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<i;j++){
				e[i][j]=e[j][i]=cal(i,j);
			}
		}
		double l=0;
		double r=100.0;
		double mid;
		while(r-l>eps){
			mid=(l+r)*0.5;
			if(prime(mid)>=0){
				l=mid;
			}else{
				r=mid;
			}
		}
		printf("%.3f\n",l);
	}
}

猜你喜欢

转载自blog.csdn.net/running_acmer/article/details/80869039