POJ 2976,3111 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 3111 

这题是上面的加强版。

二分最后一个的肯定是符合的,所以最后一种已经排序好的直接输出就行了。

刚开始T了,然后用了部分排序过了,原来是怕下标没排好序,所以自己又排了下就T了。不过用了部分排序反而时间更慢了。还是用快速排序比较快。如果二分上界是v[i]的和的话更加快!

#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 100005
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,k;
double a[maxn],b[maxn];
struct abc
{
    int i;
    double w;
    bool operator<(const abc &a)const
    {
        return w>a.w;
    }
}val[maxn];
double check(double r)
{
    for(int i=0; i<n; i++)
        val[i].w=a[i]-b[i]*r,val[i].i=i;
    sort(val,val+n);//比下面的部分排序还快
    //partial_sort(val,val+k,val+n);
    double sum=0;
    for(int i=0; i<k; i++)
        sum+=val[i].w;
    return sum;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=0; i<n; i++)
        scanf("%lf%lf",a+i,b+i);
    double l=0,r=INF,mid;
    while(r-l>eps)
    {
        mid=(l+r)/2.0;
        if(check(mid)>=0) l=mid;
        else r=mid;
    }
    printf("%d",val[0].i+1);
    for(int i=1;i<k;i++)
        printf(" %d",val[i].i+1);
    puts("");
    return 0;
}




你可能感兴趣的:(POJ 2976,3111 01分数规划)