POJ 2728 Desert King【最优比率生成树,迭代加深】

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/84839148

链接

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


大意

给定 n n 个点的高度和坐标
若高度差为价值,记为 C i , j = h i h j C_{i,j}=|h_i-h_j|
若坐标差为代价,记为 R i , j = ( x i x j ) 2 + ( y i y j ) 2 R_{i,j}=\sqrt{(x_i-x_j)^2+(y_i-y_j)^2}
试找出一个 a n s ans ,使得图中的一个生成树集合的 C ( m i d × R ) \frac{\sum C}{\sum (mid\times R)} 最小

数据范围:
n 1000 n\leq1000


思路

首先比较容易发现数据是具有单调性的,那么我们可以二分

而若我们需要满足题目所说的生成树,那么这棵树必然是一棵最大生成树,所以我们可以建 C i , j R i , j × m i d C_{i,j}-R_{i,j}\times mid 的边,然后求最大生成树,判断结果非负即可

由于数据比较大,所以得用 p r i m prim 本题还可以用迭代加深继续优化,不过本蒟蒻太菜,不会。。。


代码

#include<cmath>
#include<cctype>
#include<cstdio>
#include<algorithm>
using namespace std;int n;
bool vis[1001];double dis[1001],zjs,mid,x[1001],y[1001],z[1001],maxn,minn;
const double eps=1e-6;
inline double power(double x){return x*x;}//平方
inline double f(register int i,register int j,double mid)//求权值
{
	return fabs(z[i]-z[j])-sqrt(power(x[i]-x[j])+power(y[i]-y[j]))*mid;
}
inline double MST(double mid)//prim算法
{
	double ans=0,minn=0x3f3f3f3f;
	int u=1,id=1;
	dis[1]=0;fill(dis+2,dis+1+n,minn);
	vis[1]=true;fill(vis+2,vis+1+n,0);//以上皆为初始化
	for(register int i=1;i<n;i++)
	{
		minn=0x3f3f3f3f;id=1;
		for(register int v=1;v<=n;v++)
		{
			if(vis[v]) continue;
			dis[v]=min(f(u,v,mid),dis[v]);//找到最短的那条
			if(dis[v]-eps<=minn)//小于精度差即可
			{
				minn=dis[v];
				id=v;
			}
		}
		ans+=minn;//加上
		vis[id]=1;//标记选过
		u=id;//记录上次选的
	}
	return ans;//返回
}
signed main()
{
	while(scanf("%d",&n),n)
	{
		minn=0x3f3f3f3f;maxn=0;
		for(register int i=1;i<=n;i++) 
		scanf("%lf %lf %lf",x+i,y+i,z+i),maxn=max(maxn,z[i]),minn=min(minn,z[i]);//输入
		mid=0.0;
		for(double l=0.0,r=n*(maxn-minn);r-l>eps;)//二分
		{
			mid=(l+r)/2.0;
			zjs=MST(mid);
			if(fabs(zjs)<eps) break;//到达要求,退出
			if(zjs<0) r=mid;else l=mid;//更新边界
		}
		printf("%0.3f\n",mid);
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/84839148
今日推荐