大意:有两组数据,求将两组数据分别相加之后和的最大值(必须满足这两组数据的和都为正)
将a[i]看作是花费,b[i]看作是价值,因为存在负值,所以进行讨论,如果a[i]大于0就相当于普通的01背包,如果a[i]小于0,则是01背包的逆(填充空间却有价值,就是要算填充空间最少时价值的最大,而01背包是消耗空间最小时价值的最大)只要将for循环倒过来,01背包完全背包for的循环条件都是在(0...V),所以(a[i],a[i]+200000)(与完全背包区分,完全背包是(0..V)因为要下表不为负所以写成(a[i]...V)),所以每一个dp[i]为以a[i]为下标的最大的价值,最后只要遍历,找到dp[i]+i-100000就是(if(dp)和i从100000遍历保证不出现sum为负的情况)比较难想,负数处理只要给定中间值,背包大小100000 = 100*1000。
(why?01背包完全背包for条件必须在(0,V)区间里面)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int inf = 0x3f3f3f3f; const int MAX = 100000+5; int dp[2*MAX]; int a[105],b[105]; int main() { int x,y; int T; while(~scanf("%d",&T)){ memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); for(int i = 1 ; i <= T; i++){ scanf("%d%d",&a[i],&b[i]); } for(int i = 0; i <= 200000;i++) dp[i] = -inf; dp[100000] = 0; for(int i = 1; i <= T; i++){ if(a[i] < 0 && b[i] < 0) continue; else if(a[i] > 0){ for(int j = 200000; j >= a[i]; j--){ if(dp[j-a[i]] > - inf){ dp[j] = max(dp[j],dp[j-a[i]] + b[i]); } } } else { for(int j = a[i]; j <= 200000+a[i]; j++){ if(dp[j-a[i]] > -inf){ dp[j] = max(dp[j],dp[j-a[i]]+b[i]); } } } } int max1 = -inf; for(int i = 100000; i <= 200000; i++){ if(dp[i] >= 0) max1 = max(max1,dp[i]+i-100000); } printf("%d ",max1); } return 0; }