POJ 2184 Cow Exhibition(0-1背包)

题目描述:
Cow Exhibition
Time Limit: 1000MS Memory Limit: 65536K

“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.

题目大意:
首先题目大意很简单,就是一个农夫有n头牛,他想带一些牛去,使得这些牛的t和f的和最大并且t的和跟f的和都要非负

题目分析:
0-1背包,传统的0-1背包就是每个个体有两个属性,这个也是,只不过有的是有负值的存在,所以可以把其中一个属性看成是重量,另外一个看成是价值
这样我们定义dp[i][j]:前i头牛,t的和为j时的f的和的最大值
由于t的和最小为-100000,最大为100000,所以我们需要把第二维整体+100000(这只是偷懒的做法,也可以是根据n的规模去调整大小,这样可以做到节省空间),这样的话就变成dp[100][200000],此时0~200000分别映射为-100000~100000,
当第i头牛的t>=0时,就是一个普通的0-1背包,此时dp[i][j]=max(dp[i][j],dp[i-1][j-cow[i].s]+cow[i].f),从这个状态转移方程看,每次在更新dp[i][j]时,都是用原始值和未加入第i头牛的时候的对应的j-j-cow[i].s处(比j小)的值去更新,那么我们就可以降维,从j的最大值开始往回更新,这样所需要的两个值都能从当前的dp数组中找到(如果从前王后的话会导致降维之后j-j-cow[i].s的值已经被更新为加入第i头牛后的结果)
同样的道理,当第i头牛对应的t<0时,j从小到大更新就好了
初值:
由于有负值的存在最大值有可能为负值,所以更新dp数组的时候要用-INF,当然,一头牛不选的时候,f和的最大值为0,映射过去的话就是dp[100000]=0;
代码:

#include "stdio.h"
#include "algorithm"
#define INF 1e8
using namespace std;
int n;
struct node
{
    int s,f;
};
node cow[100+5];
int dp[200000+5];
int main()
{
    int i,j;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&cow[i].s,&cow[i].f);
        }
        fill(dp,dp+200000+5,-INF);
        dp[100000]=0;
        for(i=1;i<=n;i++)
        {
            if(cow[i].s>=0){
            //从后往前更新
                for(j=200000;j>=cow[i].s;j--)
                {
                    dp[j]=max(dp[j],dp[j-cow[i].s]+cow[i].f);
                }
            }else{
            //从前往后更新
                for(j=0;j-cow[i].s<=200000;j++)
                {
                    dp[j]=max(dp[j],dp[j-cow[i].s]+cow[i].f);
                }
            }

        }
        int mx=0;
        for(i=100000;i<=200000;i++)
        {
            if(dp[i]>=0)
                mx=max(mx,dp[i]+i-100000);
        }
        printf("%d\n",mx);

    }
    return 0;
}

你可能感兴趣的:(dp,poj,0-1背包)