首页 > 代码库 > POJ 2976 01分数规划

POJ 2976 01分数规划

转自魏神:

题目大意就 给定n个二元组(a,b),扔掉k个二元组,使得剩下的a元素之和与b元素之和的比率最大

题目求的是 max(∑a[i] * x[i] / (b[i] * x[i]))  其中a,b都是一一对应的。 x[i]取0,1  并且 ∑x[i] = n - k;

那么可以转化一下。  令r = ∑a[i] * x[i] / (b[i] * x[i])  则必然∑a[i] * x[i] - ∑b[i] * x[i] * r= 0;(条件1)

 并且任意的 ∑a[i] * x[i] - ∑b[i] * x[i] * max(r) <= 0  (条件2,只有当∑a[i] * x[i] / (b[i] * x[i]) = max(r) 条件2中等号才成立)

然后就可以枚举r , 对枚举的r, 求Q(r) = ∑a[i] * x[i] - ∑b[i] * x[i] * r  的最大值,  为什么要求最大值呢?  因为我们之前知道了条件2,所以当我们枚举到r为max(r)的值时,显然对于所有的情况Q(r)都会小于等于0,并且Q(r)的最大值一定是0.而我们求最大值的目的就是寻找Q(r)=0的可能性,这样就满足了条件1,最后就是枚举使得Q(r)恰好等于0时就找到了max(r)。而如果能Q(r)>0 说明该r值是偏小的,并且可能存在Q(r)=0,而Q(r)<0的话,很明显是r值偏大的,因为max(r)都是使Q(r)最大值为0,说明不可能存在Q(r)=0了,需要换方向搜索了、 

然后算法框架就出来了。

二分枚举r。对每个r。求出每个a[i] - b[i] * r; 然后排序,将最大的n-k个相加即为最Q(r)的最大值。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define eps 1e-7
#define INF 0x7fffffff
#define maxn 1005
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,k;
double a[maxn],b[maxn],val[maxn];
double check(double r)
{
    for(int i=0;i<n;i++)
        val[i]=a[i]-b[i]*r;
    sort(val,val+n,greater<double>());
    double sum=0;
    for(int i=0;i<n-k;i++)
        sum+=val[i];
    return sum;
}
int main()
{
    while(scanf("%d%d",&n,&k)&&(n||k))
    {
        for(int i=0;i<n;i++)
            scanf("%lf",a+i);
        for(int i=0;i<n;i++)
            scanf("%lf",b+i);
        double l=0,r=1,mid;
        while(r-l>eps)
        {
            mid=(l+r)/2.0;
            if(check(mid)>=0) l=mid;
            else r=mid;
        }
        printf("%d\n",(int)(mid*100+0.5));
    }
    return 0;
}



POJ 2976 01分数规划