有一群奶牛,每一头都有s[i], f[i]两个值。在其中找一个子集,要在保证这两个值均为非负的情况下,使s和f的总和最大。
http://poj.org/problem?id=2184
这是01背包的变形,因为有负值的存在,背包的体积为-100000~100000
我们可以将区间平移到0~200000,原点就变成了100000
在进行01背包时,dp[v] = max(dp[v], dp[v - c[i]] + w[i],要用dp[v - c[i]]更新dp[v],所以要从大到小遍历。
但当c[i] < 0时,要从小到大遍历,因为v - c[i] > v。
在遍历结果的时候要从新的原点100000开始
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, s[1000 + 10], f[1000 + 10], dp[200000 + 10];
int main(){
scanf("%d", &n);
for(int i=0; i<n; i++){
scanf("%d%d", &s[i], &f[i]);
}
for(int i=0; i<=200000; i++) dp[i] = -inf;
dp[100000] = 0;
for(int i=0; i<n; i++){
if(s[i] > 0){
for(int j=200000; j>=s[i]; j--) dp[j] = max(dp[j], dp[j - s[i]] + f[i]);
}
else{
for(int j=0; j<=200000+s[i]; j++) dp[j] = max(dp[j], dp[j - s[i]] + f[i]);
}
}
int ans = 0;
for(int i=100000; i<=200000; i++){
if(dp[i] > 0) ans = max(dp[i] + i - 100000, ans);
}
printf("%d\n", ans);
return 0;
}