您的位置:首页 > 其它

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

2015-11-11 17:43 281 查看
@(K ACMer)

题意:

有n个物品,他们有两个属性,聪明值和有趣值,选择他们中的一些物品让聪明值和有趣值的和最大且聪明值或者有趣值的和不能为负数.

分析:

这个问题的精华在于讲原问题,转化为等价问题:dp[i]表示聪明值为i时有趣值的最大值.最后再来扫描整个数组,求满足条件的即可.

转移方程如下:

dp[i]=max(dp[i],dp[i−s[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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp