大致题意:给num头牛的S和F值(-1000 <= S,F <= 1000),要求从中选出几头牛,使S的总值TS和F的总值都不为负并且和最大。
方法:01背包,因为有负数,所以要将范围变成(0, 200000),在w[i]大于0时,应该逆序,小于0时,应该顺序。为什么是顺序呢,因为减掉一个负数就是等于加上一个正数,所以就是更新的时候是要用到上一层后面的数,所以是顺序。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf = -2320000;
int dp[200100];
int w[110], v[110], n;
int main(){
int i, j;
while(scanf("%d", &n) == 1){
for(i = 0; i <= 200000; i++)
dp[i] = inf;
dp[100000] = 0;
for(i = 1; i <= n; i++){
scanf("%d%d", &w[i], &v[i]);
}
for(i = 1; i <= n; i++){
if(w[i] > 0){//正的时候是逆序
for(j = 200000; j >= w[i]; j--)
if(dp[j-w[i]] != inf)
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
}
else{//负的时候是顺序
for(j = 0; j <= 200000+w[i]; j++)
if(dp[j-w[i]] != inf)
dp[j] = max(dp[j], dp[j-w[i]]+v[i]);
}
}
int res = 0;
for(i = 100000; i <= 200000; i++){
if(dp[i]>=0 && dp[i]+i-100000>res)
res = dp[i]+i-100000;
}
printf("%d\n", res);
}
return 0;
}