poj 2184
真是一个好题啊,还是想了好几天而且还WA了两次…….
令res[i][j]表示前i个COW,Si为j时Fi的最大值。
res[i][j]=max(res[i-1][j-Fi[i]],res[i][j]); 因为res[i][]只与res[i-1][]有关空间复杂度省去一维,就像01背包那样。因为j可能为负值,因此我们可以将j设置一个偏移量MOVE。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define MAX 1234567890 #define MOVE 100000 int Si[110],Fi[110],res[200010]; int max(int a,int b) { return a > b ? a : b; } int work(int n,int end,int start) { int i,j,Max; for(i=start;i<=end;i++) res[i]=-MAX; for(i=1;i<=n;i++) { if(Si[i]>0) { for(j=end;j>=start+Si[i];j--) { if(res[j-Si[i]]!=-MAX) res[j]=max(res[j-Si[i]]+Fi[i],res[j]); } res[MOVE+Si[i]]=max(Fi[i],res[MOVE+Si[i]]); } else { for(j=start;j<=end+Si[i];j++) { if(res[j-Si[i]]) res[j]=max(res[j-Si[i]]+Fi[i],res[j]); } res[MOVE+Si[i]]=max(Fi[i],res[MOVE+Si[i]]); } } Max=0; for(i=MOVE;i<=end;i++) { if(res[i]>=0 && i-MOVE+res[i] > Max ) Max=i-MOVE+res[i]; } return Max; } int main() { int i,n,sum1,sum2,f,s; while(scanf("%d",&n)!=EOF) { sum1=sum2=0; memset(res,0,sizeof(res)); for(i=1;i<=n;i++) { scanf("%d %d",&s,&f); Si[i]=s; Fi[i]=f; s > 0 ? sum1+=s : sum2+=s; } printf("%d\n",work(n,sum1+MOVE,sum2+MOVE)); } return 0; }