Talent Show(01分数规划)

原题: http://acm.zjnu.edu.cn/CLanguage/showproblem?problem_id=2268

n个物品,w值与v值,要求 w > = W \sum_w>=W 的前提下 v / w \sum_v/\sum_w 最大

比赛的时候感觉没没没问题啊。。。01分数规划白学了。

解析:

先01分数规划,再dp即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(register int i=a;i<=b;i++)
int n,W;
int w[260],v[260];
struct node{
    double val,w;
    bool operator<(const node &rhs)const{
        return val>rhs.val;
    }
}e[260];
const double eps=1e-7;

double dp[1009];
bool check(double x){
    rep(i,1,n){
        e[i].w=1.0*w[i];
        e[i].val=1.0*v[i]-x*w[i];
    }
    sort(e+1,e+1+n);
    int i=1;
    double sumv=0;
    double sumw=0;
    for(;i<=n;i++){//大于0的一定要选
        if(e[i].val>=0)sumv+=e[i].val,sumw+=e[i].w;
        else break;
    }
    if(sumw>=W)return 1;
    int en=(int)round(1.0*W-sumw);
    rep(i,1,en)dp[i]=-1e18;
    dp[0]=0;
    for(;i<=n;i++){
        for(int j=en;j>=0;j--){
            int to=j+e[i].w;
            if(to>en)to=en;
            dp[to]=max(dp[to],dp[j]+e[i].val);
        }
    }
    if(dp[en]+sumv>0)return 1;
    return 0;
}

int main(){
    cin>>n>>W;
    double l=1e18,r=-1e18;
    rep(i,1,n){
        scanf("%d%d",w+i,v+i);
        l=min(l,1.0*v[i]/w[i]);
        r=max(r,1.0*v[i]/w[i]);
    }
    while(r-l>eps){
        double mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid;
    }
    printf("%.0f\n",floor(r*1000.0));
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/88418863