poj 2728 Desert King(最优比率生成树)

106 篇文章 0 订阅
64 篇文章 0 订阅

题意:

有n个点,要求一棵生成树使总height/distance最小,height为两点高度差,distance为两点间距离,输出最小的height/distance。


解题思路:

这题是01规划在最小生成树中的应用,我们按照01规划的方法不断求优化斜率,在更新斜率的时候用求最小生成树的做法去使height-l*distance(l就是斜率,即要求的答案)的值最大,然后更新l到不能再更新为止就可以了。

不会01规划的可以去看这篇博客

http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html

代码:

#include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>

    using namespace std;
    const int maxn=1005;
    const double eps=1e-9;
    int top;
    int n;

    struct p
    {
        double x;
        double y;
        double z;
    }a[maxn];
    struct node
    {
        int x;
        int y;
        double c;
        double d;
        double e;
    }edg[maxn*maxn];//边数是点数的平方
    int f[maxn];
    int getf(int x)
    {
        if(x==f[x])return x;
        else return f[x]=getf(f[x]);
    }

    bool merg(int x, int y)
    {
        int a=getf(x);
        int b=getf(y);
        if(a!=b)
        {
            f[a]=b;
            return 1;
        }
        else return 0;
    }

    double dis(int x, int y)
    {
        return sqrt((a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[x].y-a[y].y)*(a[x].y-a[y].y));
    }

    bool cmp(node a, node b)
    {
        return a.e<b.e;
    }

    double ff(double l)
    {
        int i, j=0;
        for(i=1; i<=n; i++)f[i]=i;
        for(i=0; i<top; i++)edg[i].e=edg[i].c-l*edg[i].d;
        sort(edg, edg+top, cmp);
        double fz=0, fm=0;
        for(i=0; i<top; i++)
        {
            if(merg(edg[i].x, edg[i].y))
            {
                fz+=edg[i].c;
                fm+=edg[i].d;
//                printf("%d %d %.3f %.3f %.3f\n", edg[i].x, edg[i].y, l, edg[i].c, edg[i].d);
                j++;
            }
            if(j==n-1)break;
        }
//        printf("%.3f\n", fz/fm);
        return fz/fm;
    }

    int main()
    {
        int i, j;
        double e, l;
        while(~scanf("%d", &n))
        {
            if(n==0)break;

            top=0;
            for(i=1; i<=n; i++)
            {
                scanf("%lf%lf%lf", &a[i].x, &a[i].y, &a[i].z);
                for(j=1; j<i; j++)
                {
                    edg[top].x=i;
                    edg[top].y=j;
                    edg[top].d=dis(i, j);
                    edg[top++].c=fabs(a[i].z-a[j].z);
                }
            }
            e=edg[0].c/edg[0].d;
            while(1)
            {
                l=ff(e);
                if(fabs(l-e)<eps)break;
                e=l;
            }
            printf("%.3f\n", l);

        }
        return 0;
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值