[POJ2976][POJ2728]01分数规划问题的二分答案解法

这里就不放原题目了。

POJ2976就是01分数规划的模板题,题目形式就是有n个物品,每个物品有对应的价值ai和代价bi,我们要取K个物品,使取的物品的  最小。

二分答案的解法特别妙,我们设 r= ,那么就有   由此不难发现,只要满足这条式子,我们能取的r越大越好。

不难发现此时已经满足二分答案的性质了。

二分r的大小,如果最后式子左边大于0,那么说明r取小了,如果左边小于0,说明r取大了。

那么我的代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int N,K;
double a[2000],b[2000];
double de[2000];
int main()
{
    while(1)
    {
        scanf("%d%d",&N,&K);
        if(N==0&&K==0)
            return 0;
        for(int i=1;i<=N;i++)
            scanf("%lf",&a[i]);
        for(int i=1;i<=N;i++)
            scanf("%lf",&b[i]);
        double l=0,r=1,mid;
        while(r-l>0.000006)
        {
            mid=(l+r)*1.0/2;
            for(int i=1;i<=N;i++)
                de[i]=a[i]-mid*b[i];
            sort(de+1,de+N+1);
            long double sum=0;
            for(int i=K+1;i<=N;i++)
                sum+=de[i];
            if(sum>0)
                l=mid;
            else
                r=mid;
        }
        printf("%.0f\n",mid*100);
    }
} 

而POJ2728就有点小意思了,它是有01划分性质的一个平面图最小生成树。准确来说,是取生成树的边第一权值的和比上边第二权值的和的最小值。

那么我们还是用上文所述的01分数规划来做,二分答案,然后把二分出来的r值带入图中,用prim去跑一遍。(机房有位大佬不肯放弃kruscal,在卡了一晚上常数之后说了句真香)

于是我的代码如下(prim未优化)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int N;
struct node{
    int x,y,z;
    friend double dis(node a,node b)
    {
        return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
    }
}po[1005];
double edge[1005][1005],tot,high[1005],lowcost[1005];
int close[1005];
double prim(double k)
{
    double cost=0,len=0;
    double sum=0;
    for(int i=1;i<=N;i++)
    {
        close[i]=1;
        lowcost[i]=abs(po[1].z-po[i].z)-edge[1][i]*k;
    }
    /*for(int i=1;i<=N;i++)
        cout<<lowcost[i]<<" ";
    cout<<endl;*/
    close[1]=-1;
    for(int i=1;i<N;i++)
    {
        double minn=1000000000;
        int v=-1;
        for(int j=1;j<=N;j++)
            if(close[j]!=-1&&lowcost[j]<minn)
            {
                v=j;
                minn=lowcost[j];
            }
        if(v!=-1)
        {
            cost+=abs(po[close[v]].z-po[v].z);
            len+=edge[close[v]][v];
            close[v]=-1;
            sum+=lowcost[v];
            for(int j=1;j<=N;j++)
            {
                double tmp=abs(po[v].z-po[j].z)-edge[v][j]*k;
                if(close[j]!=-1&&tmp<lowcost[j])
                {
                    lowcost[j]=tmp;
                    close[j]=v;
                }
            }
        }
    }
    //cout<<k<<" "<<sum<<endl;
    return sum;
}
int main()
{
    while(1)
    {
        scanf("%d",&N);
        if(N==0)
            return 0;
        for(int i=1;i<=N;i++)
            scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].z);
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                edge[i][j]=dis(po[i],po[j]);
        double l=0.0,r=100.0,mid;
        while(r-l>1e-6)
        {
            mid=(l+r)/2;
            if(prim(mid)>=0)
                l=mid;
            else
                r=mid;
        }
        printf("%.3f\n",l);
    }
}

原文地址:https://www.cnblogs.com/sherrlock/p/9631693.html

时间: 2024-10-28 16:49:45

[POJ2976][POJ2728]01分数规划问题的二分答案解法的相关文章

[转]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

poj2976(01分数规划)

题目连接:http://poj.org/problem?id=2976 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=1010; 6 double a[maxn],b[maxn],d[maxn]; 7 int n,k; 8 bool check(double x) 9 { 10 double ans=0; 11 fo

专题:01分数规划

poj2976 普通的01分数规划 大意:给定A数组B数组,从中选择N-K个使得R最大,输出Round(100*R); #include <iostream> #include <algorithm> #include <cmath> #include <cstdio> using namespace std; const int N = 1009; const double Eps = 1e-7; int n, k; double a[N], b[N];

01分数规划学习笔记

01分数规划学习笔记 http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html [Poj2976 普通01分数规划] [Poj2728 最优比率生成树] TBD 原文地址:https://www.cnblogs.com/wuyuanyuan/p/8467899.html

poj2728 Desert King --- 01分数规划 二分水果。。

这题数据量较大,普通的求MST是会超时的. d[i]=cost[i]-ans*dis[0][i] 据此二分. 但此题用Dinkelbach迭代更好 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> using namespace std; #define N 1010 double mp[N][N],c[N][N],x

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

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

[poj2976]Dropping tests(01分数规划,转化为二分解决)

题意:有n场考试,给出每场答对的题数a和这场一共有几道题b,求去掉k场考试后,公式.的最大值 解题关键:01分数规划,double类型二分的写法(poj崩溃,未提交) 或者r-l<=1e-3(右边是精度) #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> #defi

Desert King POJ2728(Prim+迭代+0-1分数规划)

[原题地址]: POJ2728 [题目大意]: 选 \(n-1\) 条边,最小化这些边的\[\frac{\sum w_i} {\sum d_i}\] 其中 \(w_i\) 为第 \(i\) 条边的花费,\(d_i\) 为这条边所连接的两个点的距离. \(w_i\) 为连接的两个点的 \(z\) 值差的绝对值, \(d_i\) 为欧几里得距离 [题解]: 这道题是0-1分数规划的经典题目 我们令\[\frac{\sum w_i} {\sum d_i}=k\] 这样二分 \(k\) 的值 将所有的边

poj2728 Desert King——01分数规划

题目:http://poj.org/problem?id=2728 第一道01分数规划题!(其实也蛮简单的) 这题也可以用迭代做(但是不会),这里用了二分: 由于比较裸,不作过多说明了. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define eps 1e-6 using namespace std; int const inf=0x3f3f3f;