soj 2142: Cow Exhibition(01背包的变形)

来源:互联网 发布:linux socket close 编辑:程序博客网 时间:2024/06/07 06:21

@(K ACMer)


题意:
有n个物品,他们有两个属性,聪明值和有趣值,选择他们中的一些物品让聪明值和有趣值的和最大且聪明值或者有趣值的和不能为负数.
分析:
这个问题的精华在于讲原问题,转化为等价问题:dp[i]表示聪明值为i时有趣值的最大值.最后再来扫描整个数组,求满足条件的即可.
转移方程如下:

dp[i]=max(dp[i],dp[is[j]]+f[j])

但是这里有一点当s[j]为负数的时候我们就应该用相反的转移顺序.因为为负数的时候它是由它右边的状态转移而来,如果我们还是和正数一样从右到左的转移顺序,就成了完全背包了.


#include <cstdio>#include <iostream>#include <cstring>#include <cstdlib>#include <string>#include <vector>#include <set>#include <map>#include <queue>#include <algorithm>using namespace std;const int maxn = 3e5, INF = 0x3fffffff, mod = 1e9 + 7;int dp[maxn], s[111], f[111];int n, ma, mi;#define mid int(1e5 + 5e4)int main(void ){    while (~scanf("%d", &n)) {        mi = ma = 0;        for (int i = 1; i <= n; i++) {            scanf("%d%d", &s[i], &f[i]);            if (s[i] <= 0 && f[i] <= 0) i--, n--;            else if (s[i] > 0) ma += s[i];            else mi += s[i];        }        for (int i = mid + mi - 1111; i <= mid + ma + 1111; i++)            dp[i] = -INF;        dp[0 + mid] = 0;        for (int i = 1; i <= n; i++) {            if (s[i] >= 0)                for (int j = ma + mid; j >= mid + mi; j--) {                    dp[j] = max(dp[j], dp[j - s[i]] + f[i]);                }            else                for (int j = mi + mid; j <= mid + ma; j++) {                    dp[j] = max(dp[j], dp[j - s[i]] + f[i]);                }        }        int ans = 0;        for (int i = mid; i <= mid + ma; i++)            if (dp[i] >= 0) ans = max(ans, dp[i] + i - mid);        printf("%d\n", ans);    }    return 0;}
1 0
原创粉丝点击