题目B 剁手党 限时:2000ms
剁手党们整天游荡在各种大小商场,有N种物品,每种物品的数量为C1,C2......Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2......Wn(Wi为整数),与之相对应的价值为P1,P2......Pn(Pi为整数)。求背包能够容纳的最大价值。
输入
第1行,2个整数,N和W中间用空格隔开。N为物品的种类,W为背包的容量。(1 <= N <= 100,1 <= W <= 50000)
第2 - N + 1行,每行3个整数,Wi,Pi和Ci分别是物品体积、价值和数量。(1 <= Wi, Pi <= 10000, 1 <= Ci <= 200)
输出
每组数据输出一行,即可以容纳的最大价值。
样例输入 | 样例输出 |
3 6 2 2 5 3 3 8 1 4 1
| 9 |
直观的多重背包
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100 + 10;
int pri[MAXN], wei[MAXN], num[MAXN];
int dp[50010], sum, n;
void zeroOnePack(int price, int weight, int sum) ///01背包
{
for (int i = sum; i >= price; i--)
dp[i] = max(dp[i], dp[i - price] + weight);
}
void completePack(int price, int weight, int sum) ///完全背包
{
for (int i = price; i <= sum; i++)
dp[i] = max(dp[i], dp[i - price] + weight);
}
void multiPack(int n, int sum) ///多重背包
{
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
{
if (pri[i] * num[i] > sum) ///只买第i种大米可以将经费花完
completePack(pri[i], wei[i], sum); ///转化为完全背包等价于无限个可取
else
{
for (int k = 1; k < num[i]; k *= 2) ///转化为01背包,系数为1,2,4...2^(k-1)
{
zeroOnePack(k * pri[i], k * wei[i], sum);
num[i] -= k;
}
if (num[i] != 0) ///最后剩余的袋数(num[i]-2^k+1)
zeroOnePack(num[i] * pri[i], num[i] * wei[i], sum);
}
}
printf("%d\n", dp[sum]);
}
void solve()
{
while(~scanf("%d%d", &n, &sum))
{
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &pri[i], &wei[i], &num[i]);
multiPack(n, sum);
}
}
int main()
{
solve();
return 0;
}