2016暑假练习——最优比例生成树

来源:POJ2728

按照题意,我们需要求一个(sum[1,n](h[i]))/(sum[1,n](d[i])最小的一颗生成树,那么这棵树到底可不可以呢?

我们采取二分的手段来获取我们的可行性

具体来说就是,我们假设我们有一个最小值,min,这个时候就有sum[1,n](h[i])>=min*sum[1,n](d[i]),移项合并同类项可以化简为:sum[1,n](h[i]-min*d[i])>=0

这样的式子就满足最小生成树的方法了


这一题使用prim比较优越,因为prim的权值计算是动态的


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n;
const int MAXN = 1010;
const double eps = 1e-8;
const double MAXDOUBLE = 1.0*0x7fffffff;
struct Village{
	int x,y;
	int h;
	Village(int x1=0,int y_=0,int z1=0):x(x1),y(y_),h(z1){}
	void ini(int x1,int y_,int z1){
		x=x1;
		y=y_;
		h=z1;
	}
}v[MAXN];
double edge[MAXN][MAXN],ans;
double d[MAXN];
int next[MAXN];
double tran(Village a,Village b){
	return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)*1.0);
}
double prim(double mid){
	double ans=0;
	double len=0;
	double sum=0;
	for(int i=1;i<=n;i++){
		next[i]=1;
		d[i]=abs(v[i].h-v[1].h)-mid*edge[1][i];
	}
	next[1]=-1;
	for(int i=1;i<n;i++){
		double dm = MAXDOUBLE;
		int dv=-1;
		for(int j=1;j<=n;j++){
			if(next[j]!=-1 && d[j]<dm){
				dm=d[j];
				dv=j;
			}
		}
		if(dv!=-1){
			ans+=abs(v[next[dv]].h-v[dv].h);
			len+=edge[next[dv]][dv];
			next[dv]=-1;
			sum+=d[dv];
			for(int j=1;j<=n;j++){
				if(next[j]!=-1&&abs(v[dv].h-v[j].h)-mid*edge[dv][j]<d[j]){
					d[j]=abs(v[dv].h-v[j].h)-mid*edge[dv][j];
					next[j]=dv;
				}
			}
		}
	}
	return sum;
}
bool judge(double mid){
	if(prim(mid)>=0) return 1;
	else return 0;
}
int main(){
	while(scanf("%d",&n)!=EOF&&n){
		int x,y,z;
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&v[i].x,&v[i].y,&v[i].h);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				edge[i][j]=tran(v[i],v[j]);
			}
		}
		double l,r,mid;
		l=0;
		r=100.0;
		while(r-l>eps){
			mid = (l+r) /2;
			if(judge(mid)) l=mid;
			else r=mid;
		}
		printf("%.3f\n",l);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值