题目描述
有 N 种物品和一个容量是 V 的背包。
物品一共有三类:
第一类物品只能用1次(01背包);
第二类物品可以用无限次(完全背包);
第三类物品最多只能用 si 次(多重背包);
每种体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行三个整数 vi,wi,si,用空格隔开,分别表示第 i 种物品的体积、价值和数量。
si=−1 表示第 i 种物品只能用1次;
si=0 表示第 i 种物品可以用无限次;
si>0 表示第 i 种物品可以使用 si 次;
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
−1≤si≤1000
样例
输入样例
4 5
1 2 -1
2 4 1
3 4 0
4 5 2
输出样例:
8
Tips:把三种状态都转化为0/1背包问题就好了,对于无限物品可以转有限物品,用二进制优化,2^0到2^32,共32种状态;
到30应该是没有unsigned int 的原因,不过这一题过了;
C++ 代码
#include<iostream>
#define max(a, b) a > b ? a : b
struct kk
{
int v, w;
}ali[20 * 1000 + 7];
int compress[52] = {};
int dp[1520] = {}, now_idx = 1;
int N, V;
int main(void)
{
compress[0] = 1;
for (int i = 1; i < 31; i++)compress[i] = compress[i - 1] << 1;//
scanf("%d %d", &N, &V);
for (int i = 0; i < N; i++)
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);//体积、价值和数量。
/*si = −1 表示第 i 种物品只能用1次;
si = 0 表示第 i 种物品可以用无限次;
si > 0 表示第 i 种物品可以使用 si 次;*/
if (-1 == c)ali[now_idx++] = { a,b };
else if (!c)
{
for (int i = 0; i < 31; i++)
if (a * compress[i] > 0 && b * compress[i] > 0)
ali[now_idx++] = { a * compress[i],b * compress[i] };
}
else
{
for (int m = 1; m <= c; m <<= 1)
ali[now_idx++] = { a * m,b * m }, c -= m;
if (c > 0)ali[now_idx++] = { a * c,b * c };
}
}
for (int i = 1; i < now_idx; i++)
for (int v = V; v >= ali[i].v; v--)
dp[v] = max(dp[v], dp[v - ali[i].v] + ali[i].w);
printf("%d\n", dp[V]);
return 0;
}