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; }