最优比例生成树

来源:互联网 发布:淘宝店铺规模排名 编辑:程序博客网 时间:2024/05/20 21:49
题目链接:http://poj.org/problem?id=2728

题目大意:有n个点,每个点(x,y,h),x,y表示这个点的坐标,h表示这个点的高度。对于任意两个点存在这样两个数据,height:高度差,len:欧几里得距离。求把n个点连起来,试任意两个点联通,且,所有边的高度差之和除以距离和值最小。


思路:二分。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 1005
#define MAX 0x7fffffff
#define MIN 1e-5
using namespace std;
struct node
{
    double x,y,h;
} p[N];
int n,vis[N];
double l,r,mid;
double dis[N][N],low[N];

void distance()
{
    int i,j;
    for(i=1; i<=n; i++)
        for(j=1; j<=n; j++)
            dis[i][j]=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));
}

int judge()
{
    double sum=0.0;
    int i,j,pos=1;
    double min;
    vis[1]=1;
    low[1]=0;
    for(i=2; i<=n; i++)
    {
        vis[i]=0;
        low[i]=MAX;
    }
    for(i=1; i<=n-1; i++)
    {
        min=MAX;
        int k;
        for(j=1; j<=n; j++)
            if(!vis[j])
            {
                if(low[j]>fabs(p[pos].h-p[j].h)-mid*dis[pos][j]);
                low[j]=fabs(p[pos].h-p[j].h)-mid*dis[pos][j];
                if(low[j]<min)
                {
                    min=low[j];
                    k=j;
                }
            }
        sum+=min;
        vis[k]=1;
        pos=k;
    }
    if(sum<=MIN)return  1;
    else return 0;
}

void slove()
{
    distance();
    l=0.0;
    r=1000.0;
    while(r-l>MIN)
    {
        mid=(l+r)*0.5;
        if(judge())r=mid;
        else l=mid;
    }
    printf("%.3lf\n",mid);
}
int main()
{
    while(scanf("%d",&n),n)
    {
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].h);
        }
        slove();
    }
    return 0;
}


0 0