poj 1973
dp[i][x]表示前i个工人,做x件A,最多能做多少件B。(空间可以优化成一维,但要注意for循环顺序,从大到小,向01背包那样!)
因为时间是通过二分枚举确定下来了。所以有转移方程:mid是枚举处的时间
dp[j]=max(dp[j],dp[j-k]+(mid-k*a[i])/b[i]);
代码:
#include<iostream> #include<fstream> using namespace std; int n,m,mid; int a[101],b[101]; int dp[101][101]; int solve(){ int i,j,k; memset(dp,-1,sizeof(dp)); for(j=0;j<=m;j++) if(mid>=j*a[1]) dp[1][j]=(mid-j*a[1])/b[1]; else dp[1][j]=-1; for(i=2;i<=n;i++) for(j=0;j<=m;j++) { for(k=0;k*a[i]<=mid&&k<=j;k++) if(dp[i-1][j-k]!=-1) { dp[i][j]=max(dp[i][j],dp[i-1][j-k]+(mid-k*a[i])/b[i]); } } if(dp[n][m]>=m) return 1; else return 0; } void read(){ // ifstream cin("in.txt"); int i,j,k; int cas; int maxx; cin>>cas; while(cas--) { cin>>n>>m; maxx=0; for(i=1;i<=n;i++) { cin>>a[i]>>b[i]; maxx=max(max(maxx,a[i]),b[i]); } i=0;j=maxx*m*2; while(i<=j) { mid=(i+j)>>1; if(solve()) j=mid-1; else i=mid+1; } cout<<i<<endl; } } int main(){ read(); return 0; }