poj 2184--Cow Exhibition

来源:互联网 发布:网络洗钱的常见方式 编辑:程序博客网 时间:2024/05/16 05:32

有一群奶牛,每一头都有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;}


0 0