POJ2184Cow Exhibition (01背包变形)

思路一下子就想到了,转移方程却没想好,看到网上一个的思路相同的代码,改的转移方程。

同时dp全部初始化为负无穷,需要注意一下。

AC代码如下:

/**************************************************
Memory: 1884 KB		Time: 250 MS
Language: G++		Result: Accepted
**************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

/**
题目描述:
n头牛(1-n),每个牛有两个值Si和Fi,选其中任意头,使s和f的和最大,其中s和f各自和都不能为负数
*/

int s[105], f[105];
int dp[200005];
int num[200005];
const int INF = 0x5f5f5f5f;

int main()
{
    int n;
    while (cin >> n)
    {
        int m = 0;

        for (int i = 0; i < n; ++i)
        {
            cin >> s[i] >> f[i];
            s[i] += 1000;   // 全部加上1000保证非负
            m += s[i];
        }

        for (int i = 0; i <= m; ++i) dp[i] = -INF;
        memset(num, 0, sizeof num);
        dp[0] = 0;      // 保证所有dp的值都是正好装满。。

        for (int i = 0; i < n; ++i)
        {
            for (int j = m; j >= s[i]; --j)   
            {
                //if (dp[j] < dp[j - s[i]] + f[i])
                if (dp[j] - num[j] * 1000 < dp[j - s[i]] + f[i] - (num[j - s[i]] + 1) * 1000)
                {   // 这转移方程我也是醉了。。保证的是s和为j时s和f的和最大
                    dp[j] = dp[j - s[i]] + f[i];
                    num[j] = num[j - s[i]] + 1;     // 记录用了多少头牛。。
                }
                //printf("dp[%d]=%d, num[%d]=%d
", j, dp[j],j, num[j]);
            }
        }

        int ans = 0;

        for (int j = 0; j <= m; ++j)
        {
            if (dp[j] >= 0 && j - num[j] * 1000 >= 0)
                ans = max(ans, dp[j] + j - num[j] * 1000);
        }

        cout << ans << endl;
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/wenruo/p/4902639.html