zoukankan      html  css  js  c++  java
  • POJ 2728 Desert King

    0/1分数规划+最小生成树

    题意

    有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小

    n <= 1000

    输入n行每行三个数x y z分别表示坐标与海拔

    题目中所给条件,可以推出任意两点间的距离和海拔差

    记$d[i][j]$表示从点i到点j的距离,$cost[i][j]$表示从点i到点j的海拔之差

    对于距离$d$数组,海拔$cost$数组,可以看做一个典型的0/1分数规划

    根据0/1分数规划的做法,二分枚举答案

    但是二分中判断函数,不只是单单的排序

    记$e[i][j]=h[i][j]-mid*cost[i][j]$

    那么判断函数就是求以e数组为图的边的最小生成树

    此处为完全图,Kruskal算法复杂度为$O(n^{2}logn^{2})$,外层二分再套个$logn$

    复杂度无法接受

    那么使用Prim算法

    那么总复杂度为$O(n^{2}logn)$

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int n,cost[1100][1100];
    double dis[1100][1100],e[1100][1100],ans;
    double lowcost[1100];
    bool vi[1100];
    struct node
    {
        int x,y,z;
    }sh[1100];
    bool check(double mid)
    {
        double sum=0.0;
        for (int i=1;i<=n;i++)
        {
            for (int j=1;j<=n;j++)
            {
                if (i==j)
                {
                    e[i][j]=0;
                    continue;
                }
                e[i][j]=(double)cost[i][j]-mid*dis[i][j];//求出e数组
            }
            vi[i]=0;
        }
        for (int i=2;i<=n;i++)
        {
            lowcost[i]=e[1][i];
        }
        vi[1]=1;
        for (int i=1;i<n;i++)//Prim算法
        {
            double MIN;
            int wh;
            MIN=1.0e9;
            for (int j=2;j<=n;j++)
            {
                if (!vi[j] && lowcost[j]<MIN)
                {
                    MIN=lowcost[j];
                    wh=j;
                }
            }
            vi[wh]=1;
            sum+=MIN;
            for (int j=2;j<=n;j++)
            {
                if (!vi[j] && e[wh][j]<lowcost[j])
                {
                    lowcost[j]=e[wh][j];
                }
            }
        }
        return sum>=0.0;
    }
    int main()
    {
        while (1)
        {
            scanf("%d",&n);
            if (n==0)
              break;
            for (int i=1;i<=n;i++)
              scanf("%d%d%d",&sh[i].x,&sh[i].y,&sh[i].z);
            for (int i=1;i<=n;i++)
            {
                for (int j=1;j<=n;j++)
                {
                    cost[i][j]=abs(sh[i].z-sh[j].z);
                    dis[i][j]=sqrt((sh[i].x-sh[j].x)*(sh[i].x-sh[j].x)+(sh[i].y-sh[j].y)*(sh[i].y-sh[j].y));
                }
            }
            double l,r,mid;
            l=0.0;
            r=1000000000.0;
            while (r-l>1.0e-6)//注意精度问题
            {
                mid=(l+r)/2;
                if (check(mid))
                {
                    l=mid;
                    ans=mid;
                }
                else
                {
                    r=mid;
                }
            }
            printf("%.3f
    ",ans);
        }
    }
  • 相关阅读:
    左偏树
    论在Windows下远程连接Ubuntu
    ZOJ 3711 Give Me Your Hand
    SGU 495. Kids and Prizes
    POJ 2151 Check the difficulty of problems
    CodeForces 148D. Bag of mice
    HDU 3631 Shortest Path
    HDU 1869 六度分离
    HDU 2544 最短路
    HDU 3584 Cube
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11265422.html
Copyright © 2011-2022 走看看