luogu 4377 Talent show 01分数规划+背包dp

01分数规划+背包dp

将分式下面的部分向右边挪过去,通过二分答案验证,

注意二分答案中如果验证的mid是int那么l=mid+1,r=mid-1,double类型中r=mid,l=mid;

背包dp中注意所有大于W的要通过min和max将答案归于W,通过dp得到该种情况的最大结果,不能用贪心

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
namespace zjc{
    int n,W,w[300],t[300];
    double v[300],f[1050];
    bool solve(double mid){
        rep(i,1,W) f[i]=-inf;
        rep(i,1,n) v[i]=t[i]-w[i]*mid;
        rep(i,1,n)dec(j,W,0) f[min(w[i]+j,W)]=max(f[min(w[i]+j,W)],f[j]+v[i]);
        return f[W]>=0;
    }
    void work(){
        n=read(),W=read();
        double l=0,r=0;
        rep(i,1,n) w[i]=read(),t[i]=read(),r+=t[i];
        while(r-l>=1e-4){
            double mid=(l+r)/2;
            if(solve(mid)) l=mid;
            else r=mid;}
        printf("%d",(int)l*1000);return;
    }
}
int main(){
    zjc::work();
    return 0;
}

 

posted @ 2018-09-12 18:51  ASDIC减除  阅读(147)  评论(0编辑  收藏  举报