[POJ 2184]Cow Exhibition[DP][01背包]

题目链接: [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;
}


你可能感兴趣的:(dp)