题目链接:
[POJ 2184]Cow Exhibition[DP][01背包]
题意分析:
有n头牛,每头牛的智商为si,情商为fi,现在要举办一个展览,需要选择一些牛出来,满足这些牛的情商只和不小于0,智商之和不小于0,并且需要这两个之和的和最大化,问最大是多少?不存在则输出0。
解题思路:
将牛的智商作为背包容量,情商作为价值,那么最终答案就是:dp[i] + i。本题智商可为负,为了使背包容量非负,我们手动给它加上值即可。
注意状态转移时,牛智商的正负要分开讨论,此时的循环方向和以往有些不同,但本质就是需要不计算重复内容。
这题由于状态的不可达,所以初始时,价值都为负无穷。
个人感受:
一直不知道负了怎么处理,这样就行了。
具体代码如下:
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<string>
using namespace std;
const int MAXN = 1e5;
struct Cow{
int s, f;
}cow[150];
int dp[2 * MAXN + 100];
int main()
{
#ifdef LOCAL
freopen("C:\\Users\\apple\\Desktop\\in.txt", "r", stdin);
#endif
int n; cin >> n;
for (int i = 0; i < n; ++i) {
cin >> cow[i].s >> cow[i].f;
}
int center = 1000 * n; // 防止负数容量特设的起始点
int up = center * 2 + 20; // 背包容量上限
memset(dp, -0x3f, sizeof(int) * (up + 1));
dp[center] = 0;
for (int i = 0; i < n; ++i) {
if (cow[i].s < 0) {
for (int j = 0; j <= up + cow[i].s; ++j) {
dp[j] = max(dp[j], dp[j - cow[i].s] + cow[i].f);
}
}
else {
for (int j = up; j >= cow[i].s; --j) {
dp[j] = max(dp[j], dp[j - cow[i].s] + cow[i].f);
}
}
}
int ans = 0;
for (int i = center; i <= up; ++i) {
// 如果状态存在,且大于最大值
if (dp[i] >= 0 && dp[i] + i - center > ans)
ans = dp[i] + i - center;
}
cout << ans << '\n';
return 0;
}