多重背包

HDU 2191

我们可以将多重背包分解为0-1背包和完全背包,当物品的(价格*数量)超过总金额时就可以看做是完全背包问题反之就可以看做是0-1背包问题。在转化成0-1背包时有个地方需要注意,我们可以把第i中物品的数量c[i]分成若干数量的集合比如物品i的数量有7种,就可以化为{1,2,4}可以用这集合里面三个元素组合成1~7中任意一种数量,分解的方法为:1,2,4,…….,c[i]-2^k+1
#include <iostream>  
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;

const int maxn = 110;
int n, m;
int dp[maxn], p[maxn], h[maxn], c[maxn];

void CompleteBack(int v, int w)
{
    for (int i=v; i <= n; i++)
    {
        dp[i] = max(dp[i], dp[i - v] + w);
    }
}

void OnePack(int v, int w)
{
    for (int i = n; i >= v; i--)
    {
        dp[i] = max(dp[i], dp[i - v] + w);
    }
}

int main()
{
    int C, k = 1, count = 0;
    cin >> C;
    while (C--)
    {
        cin >> n >> m;//经费 种类
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= m; i++)
        {
            cin >> p[i] >> h[i] >> c[i];//价格 重量 数量
            if (p[i] * c[i] >= n)
                CompleteBack(p[i], h[i]);//完全背包
            else
            {   
                for (int j = 1; j <=c[i]; (j<< 1))
                {
                    OnePack(j*p[i], j*h[i]);//0-1背包
                    c[i] = c[i] - j;
                }
                OnePack(p[i] * c[i], h[i] * c[i]);              
            }
        }
        cout << dp[n] << endl;
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值