这题。。。敲完都快和人家的代码一模一样了。真的,这题对于现在的我来说只能是学习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;
}