POJ2184 动态规划 01背包

题意:
某物 i , 有两种属性值 s[i] 和 f[i] ,每件物品可取或不取,求最后S + F的最大值,同时保证S >= 0 且 F >= 0。(S 为取出的 s[i] 的总和, F为取出的 f[i] 的总和)
思路:
1、涉及到取与不取的问题,很自然地想到了背包。
“物品的价值”这个显而易见,但是“背包的容量”在哪里?我们可以把两个维度 T 和 S,任取一个当作“物品的价值”,另一个做“背包的容量”,而容量最大值自然是这个属性所有正数之和。
即dp[i]:当 f 属性之和为 i 时, s 属性之和的最大值。
2、至于负数问题, 将数组开成最大值的两倍即迎刃而解。
3、坑点:01背包第二重循环因 f[i] 的正负不同, 循环方向也不同。
反思:
代码:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 100 + 10;
const int MAXM = 100 * 1000 * 2 + 1000;
int dp[MAXM];
int n;
int f[MAXN], s[MAXN];
int maxf;
int solve()
{
    dp[100000] = 0;
    for(int i = 0; i < n; i++)
    {
        if(f[i] >= 0)
        {
            for(int j = maxf; j >= f[i]; j--)
            {
                if(dp[j - f[i]] != -INF)
                {
                    dp[j] = max(dp[j], dp[j - f[i]] + s[i]);
                    //cout << "j: " << j << "  dp[j]: " << dp[j] << endl;
                }
            }
        }
        else
        {
            for(int j = f[i]; j + f[i] <= maxf; j++)
            {
                if(dp[j - f[i]] != -INF)
                {
                    dp[j] = max(dp[j], dp[j - f[i]] + s[i]);
                    //cout << "j: " << j << "  dp[j]: " << dp[j] << endl;
                }
            }
        }
    }
    int maxs = 0;
    bool flag = false;
    for(int i = 100000; i <= maxf; i++)
    {
        if(dp[i] == -INF) continue;
        else
        {
            if(dp[i] >= 0 && i - 100000 + dp[i] > maxs)
            {
                maxs = i - 100000 + dp[i];
                flag = true;
            }
        }
    }
    if(flag)
        return maxs;
    else return 0;
}
int main()
{
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d %d", &s[i], &f[i]);
        if(f[i] > 0) maxf += f[i];
    }
    maxf += 100000;
    for(int i = 0; i < MAXM; i++)
    {
        dp[i] = -INF;
    }
    printf("%d\n", solve());
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值