POJ2728Desert King

最优比率生成树问题,就是01分数规划在树上的应用

是一类求解在树上选一些边,是这些边的花费比长度最大的问题,多次prime就好

代码

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=2050;
const double eps=1e-7;
int n,vis[M];
double maxx;
double x[M],y[M],z[M],map[M][M];
double cost[M][M],len[M][M],dis[M];
double dpow(int i,int k)
{
	return (double)sqrt((x[i]-x[k])*(x[i]-x[k])+(y[i]-y[k])*(y[i]-y[k]));
}
void built()
{
	maxx=0.0;
	for (int i=1;i<=n;i++)
		for (int k=i+1;k<=n;k++)
			cost[i][k]=cost[k][i]=fabs(z[i]-z[k]),len[k][i]=len[i][k]=dpow(i,k),maxx=max(maxx,cost[i][k]/len[i][k]);
	return ;
}
double prime()
{
	for (int i=1;i<=n;i++) dis[i]=map[1][i];
	fill(vis,vis+n+1,0);vis[1]=1;double ans=0;
	for (int i=2;i<=n;i++)
	{
		double minn=0x3f3f3f;
		int get;
		for (int k=1;k<=n;k++)
		{
			if (!vis[k]&&dis[k]<minn)
				get=k,minn=dis[k];
		}
		if (minn==0x3f3f3f) break;
		vis[get]=1;ans+=minn;
		for (int k=1;k<=n;k++)
			if (!vis[k])
				dis[k]=min(dis[k],map[get][k]);
	}
	return ans;
}
bool check(double mid)
{
	for (int i=1;i<=n;i++)
		for (int k=i+1;k<=n;k++)
			map[i][k]=map[k][i]=cost[i][k]-mid*len[i][k];
	return prime()>=0;
}
int main()
{
	while (~scanf("%d",&n)&&n)
	{
		for (int i=1;i<=n;i++)
			cin>>x[i]>>y[i]>>z[i];
		built();
		double l=0.0,r=maxx;
		while (r-l>=eps)
		{
			double mid=(l+r)/2.0;
			if (check(mid)) l=mid;
			else r=mid;
		}
		printf("%.3lf\n",l);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/acerandaker/article/details/80908188