hdu3591 The trouble of Xiaoqian(多重背包 + 完全背包)

这题。。。敲完都快和人家的代码一模一样了。真的,这题对于现在的我来说只能是学习T T

虽然做过好多基本背包,但两个背包放一起对我来讲就完全不一样了,还是自己弱啊。。。这个题解真的不错


有几个注意的地方:

1、所买物品价值最大10000,但其并不是背包容量。因为我们的dp1代表的是小茜所付的钱,其实和物品价格没关系,而是她的最大消费值20000。同理dp1和dp2大小就应该开到20000。背包容量为20000。

2、以前遍历的背包都是相同体积求最大价值,而这次既然小茜付的钱为背包容量,那就应该是求背包最小价值,max函数变为min。

3、01背包中判断放的条件所产生的变化,原本是应该减去体积加上价值,但是这里居然是加上该中面值硬币的数量,怎么也想不通,暂且理解为因为是最后求的是硬币数,所以消耗的体积转化为数量。完全背包也是如此。至于为何01背包是+sum,完全背包是+1,我也不知道T T(完全背包好理解,物品数量无限所以一个一个加。但是01背包为什么不能一个一个加?以后再想吧。。。)。

#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 10005;
const int INF = 1e8;

int sum = 20000;

void ZeroOnePack(int *dp, int cost, int amount)
{
    for(int i = sum; i >= cost; i --)
        dp[i] = min(dp[i], dp[i - cost] + amount);
}

void CompletePack(int *dp, int cost)
{
    for(int i = cost; i <= sum; i ++)
        dp[i] = min(dp[i], dp[i - cost] + 1);
}

void MulPack(int *dp, int cost, int amount)
{
    if(cost * amount >= sum) //如果背包能满
    {
        CompletePack(dp, cost);
        return;
    }
    int i = 1;
    while(i < amount)
    {
        ZeroOnePack(dp, i * cost, i);
        amount -= i;
        i <<= 1;
    }
    ZeroOnePack(dp, amount * cost, amount);
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    int n, t, Case = 1;
    int dp1[sum + 5], dp2[sum + 5], a[N], val[N], num[N];
    while(~scanf("%d%d", &n, &t) && n && t)
    {
        //输入
        for(int i = 1; i <= n; i ++)
            scanf("%d", &val[i]);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &num[i]);
        //初始化
        for(int i = 0; i <= sum; i ++)
            dp1[i] = dp2[i] = INF;
        dp1[0] = dp2[0] = 0;
        //调用两种背包
        for(int i = 1; i <= n; i ++)
            MulPack(dp1, val[i], num[i]);
        for(int i = 1; i <= n; i ++)
            CompletePack(dp2, val[i]);
        //求答案
        int ans = dp1[t];
        for(int i = t + 1; i <= sum; i ++)
            ans = min(ans, dp1[i] + dp2[i - t]);
        //输出
        printf("Case %d: ", Case ++);
        if(ans == INF) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值