牛顿迭代法代替二分 pku2728高度和除以距离和最小的生成树

       题意:在二维平面内有一些点,每个点都有一个高度(变成三维了),现要找一个生成树,使得高度和除以距离和最小。(n<=1000,x,y<10000, z<10000000) 

       分析:二分比值,然后求最小生成树,判断结果是否大于0。。。用二分会超时,用牛顿迭代法,实质是不断逼近迭代。

#include<stdio.h>
#include<queue>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn=1100;
struct point
{
	double x,y,z;
}p[maxn];

int n;
double d[maxn][maxn],h1[maxn],d1[maxn],h[maxn][maxn];

double Abs(double a)
{
	return a>0? a:-a;
}
int main()
{
	int i,j,k;
	bool flag[maxn];
	double mid,sumh,sumd;
	while(scanf("%d",&n)!=EOF)
	{
		if(!n) break;
		for(i=0;i<n;i++)
			scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
		for(i=0;i<n;i++)//计算任意两点的高度差与平面坐标的距离
		{
			h[i][i]=0;
			d[i][i]=0;
			for(j=i+1;j<n;j++)
			{
				h[i][j]=h[j][i]=Abs(p[i].z-p[j].z);
				d[i][j]=d[j][i]=sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
			}
		}

		mid=0;//迭代求最后的比值
		while(1)
		{
			memset(flag,false,sizeof(flag));
			for(i=0;i<n;i++)
			{
				h1[i]=h[0][i];
				d1[i]=d[0][i];
			}
			flag[0]=true;
			for(sumh=0,sumd=0,i=1;i<n;i++)
			{
				j=1;
				while(flag[j]) j++; 
				k=j;
				for(j++;j<n;j++)//每次加入最小的
					if(!flag[j]&&h1[j]-mid*d1[j]<h1[k]-mid*d1[k])
						k=j;
				flag[k]=true;
				sumh+=h1[k];//总高度
				sumd+=d1[k];//总距离
				for(j=1;j<n;j++)//更新
					if(!flag[j]&&h1[j]-mid*d1[j]>h[k][j]-mid*d[k][j])
					{
						h1[j]=h[k][j];
						d1[j]=d[k][j];
					}
			}
			if(fabs(mid-sumh/sumd)<0.00001) break;
			mid=sumh/sumd;//迭代
		}
		printf("%.3lf\n",mid);
	}
	return 0;
}


 

        

你可能感兴趣的:(struct,ini)