POJ2184——背包DP——Cow Exhibition

Description

"Fat and docile, big and dumb, they look so stupid, they aren't much 
fun..." 
- Cows with Guns by Dana Lyons 

The cows want to prove to the public that they are both smart and fun. In order to do this, Bessie has organized an exhibition that will be put on by the cows. She has given each of the N (1 <= N <= 100) cows a thorough interview and determined two values for each cow: the smartness Si (-1000 <= Si <= 1000) of the cow and the funness Fi (-1000 <= Fi <= 1000) of the cow. 

Bessie must choose which cows she wants to bring to her exhibition. She believes that the total smartness TS of the group is the sum of the Si's and, likewise, the total funness TF of the group is the sum of the Fi's. Bessie wants to maximize the sum of TS and TF, but she also wants both of these values to be non-negative (since she must also show that the cows are well-rounded; a negative TS or TF would ruin this). Help Bessie maximize the sum of TS and TF without letting either of these values become negative. 

Input

* Line 1: A single integer N, the number of cows 

* Lines 2..N+1: Two space-separated integers Si and Fi, respectively the smartness and funness for each cow. 

Output

* Line 1: One integer: the optimal sum of TS and TF such that both TS and TF are non-negative. If no subset of the cows has non-negative TS and non- negative TF, print 0. 

Sample Input

5
-5 7
8 -6
6 -3
2 1
-8 -5

Sample Output

8

Hint

OUTPUT DETAILS: 

Bessie chooses cows 1, 3, and 4, giving values of TS = -5+6+2 = 3 and TF 
= 7-3+1 = 5, so 3+5 = 8. Note that adding cow 2 would improve the value 
of TS+TF to 10, but the new value of TF would be negative, so it is not 
allowed. 
 大意:有两组数据,求将两组数据分别相加之后和的最大值(必须满足这两组数据的和都为正)
将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;
}
View Code
原文地址:https://www.cnblogs.com/zero-begin/p/4447966.html