POJ-2728-Desert King

POJ-2728-Desert King

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

有N個村莊,給出每個村莊的座標和海拔,,benifit爲兩點之間的距離,cost爲兩點的高度差,現在要求一棵樹使得 cost / benift 最小,即求一個最優比例生成樹

第一次遇見這種生成樹,在網上找了個解法

假設sigma(h)/sigma(l)==K 均值K可取,即: sigma(h)==K*sigma(l)

 sigma(h)==K*(l1+l2+l3+...lm)

 sigma(h)==K*l1+K*l2+K*l3+...K*lm

 把原來的每個邊的h都減去K*l

 即hi'=hi-li'==hi-li*K

 然後問題可以轉換到求hi'這些邊的最小生成樹了

如果hi'這些邊得最小生成樹權值和<=0.0,說明K這個均值可取

對於k,二分求解即可

代碼基本是模仿網上的

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
#define MAXN 1010
#define INF 9999999999
struct Point
{
	double x,y,h;
};
Point point[MAXN];
double mat[MAXN][MAXN];
double h[MAXN][MAXN];
double l[MAXN][MAXN];
int n;
double head,tail;
double dist(Point &a,Point &b)
{
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double prim()
{
	int i,j,k;
	double ans=0.0,min;
	int visit[MAXN];
	double dis[MAXN];
	for(i=0;i<n;i++)
	{
		dis[i]=mat[0][i];
		visit[i]=0;
	}
	dis[0]=1;
	visit[0]=1;
	for(i=1;i<n;i++)
	{
		min=INF;
		for(j=0;j<n;j++)
		if(!visit[j]&&dis[j]<min)
		{
			min=dis[j];
			k=j;
		}
		ans+=min;
		visit[k]=1;
		for(j=0;j<n;j++)
		if(!visit[j]&&dis[j]>mat[k][j])
		dis[j]=mat[k][j];
	}
	return ans;
}
int main()
{
	int i,j;
	double maxc,minc,maxl,minl,mid;
	while(scanf("%d",&n),n)
	{
		maxc=-INF;
		minc=INF;
		maxl=-INF;
		minl=INF;
		for(i=0;i<n;i++)
		scanf("%lf%lf%lf",&point[i].x,&point[i].y,&point[i].h);
		for(i=0;i<n-1;i++)
		for(j=i+1;j<n;j++)
		{
			h[i][j]=h[j][i]=fabs(point[i].h-point[j].h);
			l[i][j]=l[j][i]=dist(point[i],point[j]);
			if(maxc<h[i][j])
			maxc=h[i][j];
			if(minc>h[i][j])
			minc=h[i][j];
			if(maxl<l[i][j])
			maxl=l[i][j];
			if(minl>l[i][j])
			minl=l[i][j];
		}
		head=minc/maxl;
		tail=maxc/minl;
		while(tail-head>1e-4)
		{
			mid=(head+tail)/2;
			for(i=0;i<n-1;i++)
			for(j=i+1;j<n;j++)
			mat[i][j]=mat[j][i]=h[i][j]-mid*l[i][j];
			if(prim()<=0.0)
			tail=mid;
			else
			head=mid;
		}
		printf("%.3f\n",head);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章