01分数规划poj2728(最优比例生成树)

Desert King

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 21766   Accepted: 6087

Description

David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his country to bring water to every village. Villages which are connected to his capital village will be watered. As the dominate ruler and the symbol of wisdom in the country, he needs to build the channels in a most elegant way.

After days of study, he finally figured his plan out. He wanted the average cost of each mile of the channels to be minimized. In other words, the ratio of the overall cost of the channels to the total length must be minimized. He just needs to build the necessary channels to bring water to all the villages, which means there will be only one way to connect each village to the capital.

His engineers surveyed the country and recorded the position and altitude of each village. All the channels must go straight between two villages and be built horizontally. Since every two villages are at different altitudes, they concluded that each channel between two villages needed a vertical water lifter, which can lift water up or let water flow down. The length of the channel is the horizontal distance between the two villages. The cost of the channel is the height of the lifter. You should notice that each village is at a different altitude, and different channels can‘t share a lifter. Channels can intersect safely and no three villages are on the same line.

As King David‘s prime scientist and programmer, you are asked to find out the best solution to build the channels.

Input

There are several test cases. Each test case starts with a line containing a number N (2 <= N <= 1000), which is the number of villages. Each of the following N lines contains three integers, x, y and z (0 <= x, y < 10000, 0 <= z < 10000000). (x, y) is the position of the village and z is the altitude. The first village is the capital. A test case with N = 0 ends the input, and should not be processed.

Output

For each test case, output one line containing a decimal number, which is the minimum ratio of overall cost of the channels to the total length. This number should be rounded three digits after the decimal point.

Sample Input

4
0 0 0
0 1 1
1 1 2
1 0 3
0

Sample Output

1.000题意:有n个村庄,分别给出每个村庄的地理坐标(xi,yi)和海拔hi,要求在村庄之间修一些河道,使这些河道联通所有的村庄,不同的村庄由于海拔的差异需要修水泵,每个水泵的费用为这两个村庄的海拔差值,且每个水泵为一条河道所用,要求所有的费用/总的河道长度比率最小分析:r=sigma(h[i][j])/sigma(l[i][j]),设R为最优值,则r>=R;(h[i][j]代表修每条河道的费用,l[i][j]代表每条河道的长度,sigma()为生成树里面的边)即:sigma(h[i][j])/sigma(l[i][j])>=R,所以:h[r]=sigma(h[i][j])-r*sigma(l[i][j])>=0;所以对于每一个r对应的h(r)的最小生成树>=0当h(r)<0的时候减小r的值,否则增大r的值,逐渐二分使h(r)=0即可;方法一:二分法
#include"stdio.h"
#include"string.h"
#include"math.h"
#define inf 0x3f3f3f3f
#define M 2009
#define eps 1e-7
struct node
{
    int x,y,h;
}p[M];
double dist(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));
}
double dis[M],G[M][M],L[M][M];
int use[M];
double dij(int n,int s)
{
    double sum=0;
    memset(use,0,sizeof(use));
    for(int i=1;i<=n;i++)
        dis[i]=inf;
    dis[s]=0;
    for(int i=1;i<=n;i++)
    {
        double mini=inf;
        int id=-1;
        for(int j=1;j<=n;j++)
        {
            if(!use[j]&&dis[j]<mini)
            {
                mini=dis[j];
                id=j;
            }
        }
        if(id==-1)break;
        sum+=dis[id];
        use[id]=1;
        for(int j=1;j<=n;j++)
        {
            if(!use[j]&&dis[j]>G[id][j])
                dis[j]=G[id][j];
        }
    }
    return sum;
}
double solve(int n,double r)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
            G[i][j]=G[j][i]=fabs(p[i].h*1.0-p[j].h*1.0)-L[i][j]*r+1000000000.0;
    }
    return dij(n,1)-(n-1)*1000000000.0;
}
int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        double l=0,r=0,mid;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].h);
            r+=p[i].h;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                L[i][j]=L[j][i]=dist(p[i],p[j]);
            }
        }
        while(r-l>eps)
        {
            mid=(l+r)/2;
            double msg=solve(n,mid);
            if(msg<0)
            {
                r=mid;
            }
            else
            {
                l=mid;
            }
        }
        printf("%.3lf\n",r);
    }
    return 0;
}

  方法二:迭代法

#include"stdio.h"
#include"string.h"
#include"math.h"
#define inf 0x3f3f3f3f
#define M 2009
#define eps 1e-6
struct node
{
    int x,y,h;
}p[M];
double dist(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y));
}
double dis[M],G[M][M],L[M][M];
int use[M],pre[M];
double dij(int n,int s)
{
    double sum=0,cost=0,leng=0;
    memset(use,0,sizeof(use));
    for(int i=1;i<=n;i++)
    {
        dis[i]=inf;
        pre[i]=-1;
    }
    dis[s]=0;
    for(int i=1;i<=n;i++)
    {
        double mini=inf;
        int id=-1;
        for(int j=1;j<=n;j++)
        {
            if(!use[j]&&dis[j]<mini)
            {
                mini=dis[j];
                id=j;
            }
        }
        if(id==-1)break;
        sum+=dis[id];
        use[id]=1;
        if(pre[id]!=-1)
        {
            cost+=fabs(p[id].h*1.0-p[pre[id]].h);
            leng+=L[id][pre[id]];
        }
        for(int j=1;j<=n;j++)
        {
            if(!use[j]&&dis[j]>G[id][j])
            {
                dis[j]=G[id][j];
                pre[j]=id;
            }
        }
    }
    return cost/leng;
}
double solve(int n,double r)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            G[i][j]=G[j][i]=fabs(p[i].h*1.0-p[j].h*1.0)-L[i][j]*r+1000000000.0;
        }
    }
    return dij(n,1);
}
int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].h);
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                L[i][j]=L[j][i]=dist(p[i],p[j]);
        double x0=0,x;
        while(1)
        {
            x=solve(n,x0);
            if(fabs(x-x0)<eps)
                break;
            x0=x;
        }
        printf("%.3lf\n",x);
    }
    return 0;
}

  

时间: 2024-10-29 10:45:42

01分数规划poj2728(最优比例生成树)的相关文章

POJ 3621 Sightseeing Cows 01分数规划,最优比例环的问题

http://www.cnblogs.com/wally/p/3228171.html 题解请戳上面 然后对于01规划的总结 1:对于一个表,求最优比例 这种就是每个点位有benefit和cost,这样就是裸的01规划 2:对于一个树,求最优比例 这种就是每条边有benefit和cost,然后通过最小生成树来判断 3:对于一个环求最优比例 这种也是每条边有benefit和cost,然后通过spfa来判断 其实01规划最核心的地方,在于构建01规划函数,构建好函数,然后根据单调性,判断大于0或者小

01分数规划(转)

01分数规划 分类: DP&&记忆化搜索2013-05-04 14:47 4193人阅读 评论(1) 收藏 举报 [关键字] 0/1分数规划.最优比率生成树.最优比率环 [背景] 根据楼教主的回忆录,他曾经在某一场比赛中秒掉了一道最优比率生成树问题,导致很多人跟风失败,最终悲剧.可见最优比率生成树是多么凶残的东西,但是这个东西只要好好研究半天就可以掌握,相信你在看了我写的这篇总结之后可以像楼教主一般秒掉这类问题. 因为网上对于01分数规划问题的详细资料并不是太多,所以我就结合自己的一些理解

【转】[Algorithm]01分数规划

因为搜索关于CFRound277.5E题的题解时发现了这篇文章,很多地方都有值得借鉴的东西,因此转了过来 原文:http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html [关键字] 0/1分数规划.最优比率生成树.最优比率环 [背景] 根据楼教主的回忆录,他曾经在某一场比赛中秒掉了一道最优比率生成树问题,导致很多人跟风失败,最终悲剧. 自己总结了一些这种问题的解法,因为水平有限,如果有错误或是麻烦的地方,尽管喷,邮箱或是下方留言

poj 2718 最优比例生成树(01分数规划)模板

/* 迭代法 :204Ms */ #include<stdio.h> #include<string.h> #include<math.h> #define N 1100 #define eps 1e-10 #define inf 0x3fffffff struct node { int u,v,w; }p[N]; double ma[N][N]; double distance(int i,int j) { return sqrt(1.0*(p[i].u-p[j].u

poj 3621 Sightseeing Cows(最优比例生成环,01分数规划)

http://poj.org/problem?id=3621 大致题意:给出一个有向图,每个点都有一个点权,每条有向边也都有一个边权,要求出一个环使得环中点权之和与边权之和的比值最大. 思路:和最优比率生成树异曲同工.设点权是v[i],边权是e[i].不同的是这里一个是点,一个是边.怎么像生成树一样把这两个值放到一起呢?可以把他们都转化到边上.同样的二分λ,每次给边重新赋权为v[i] - λ*e[i](v[i]是该边终点的点权).因为要求比值最大,那么在这前提下于图中的所有环都<=0, 所以我们

POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一条路即可,建造水管距离为坐标之间的欧几里德距离,费用为海拔之差,现在要求方案使得费用与距离的比值最小,很显然,这个题目是要求一棵最优比率生成树. 解题思路: 对答案进行二分,当把代进去的答案拿来算最小生成树的时候,一旦总路径长度为0,就是需要的答案. 0-1规划是啥? 概念有带权图G, 对于图中每条

[转]01分数规划算法 ACM 二分 Dinkelbach 最优比率生成树 最优比率环

01分数规划 前置技能 二分思想最短路算法一些数学脑细胞?问题模型1 基本01分数规划问题 给定nn个二元组(valuei,costi)(valuei,costi),valueivaluei是选择此二元组获得的价值(非负),costicosti是选择此二元组付出的代价(非负),设xi(xi∈{0,1})xi(xi∈{0,1})代表第ii个二元组的选与不选,最大(小)化下式 maximize(or minimize)   r=∑valuei?xi∑costi?ximaximize(or minim

[POJ 2728]Desert King(0-1分数规划/最优比率生成树)

Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his country to bring water to every village. Villages which are connected to his capital village will be

POJ 2728 Desert King (最优比率生成树---01分数规划)

题目地址:POJ 2728 01分数规划的应用之一-最优比率生成树. 跟普通的01分数规划类似,只是这题的验证函数改成了最小生成树来验证.弱用的迭代法. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map>