[C++]01背包问题

文章目录

  • 1.基本问题
    • 1.1 思路
    • 1.2 核心代码
  • 2.求方案数
  • 3.求装得尽量满
  • 4.求所有体积可能

1.基本问题

有N件物品和一个容量为V 的背包。放入第 i i i件物品耗费的空间是 C i C_i Ci,得到的价值是 W i W_i Wi。求解将哪些物品装入背包可使价值总和最大。

1.1 思路

这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。 用子问题定义状态:即 F [ i , v ] F[i,v] F[i,v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
F [ i , v ] = m a x { F [ i − 1 , v ] , F [ i − 1 , v − C i ] + W i } F[i, v] = max\{F[i−1,v], F[i−1,v−C_i] + W_i\} F[i,v]=max{F[i1,v],F[i1,vCi]+Wi}

1.2 核心代码

memset(F[0], 0, sizeof(F[0]));
for (int i = 1; i <= n; ++i) {
	for (int v = 0; v <= V; ++v) {
		if (v >= c[i]) F[i][v] = max(F[i-1][v], F[i-1][v-c[i]] + w[i]);
		else F[i][v] = F[i-1][v];
	}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[n][i]);

其时间复杂度和空间复杂度都是 O ( N V ) O(NV) O(NV), 其中时间复杂度基本上不能再优化了,但空间复杂度却可以优化到 O ( V ) O(V) O(V)

memset(F, 0, sizeof(F));
for (int i = 1; i <= n; ++i) {
	for (int v = V; v >= c[i]; --v) {
		F[v] = max(F[v], F[v-c[i]] + w[i]);
	}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[i]);

2.求方案数

看一道题:小A点菜
对于这类改变问法的问题,一般只需将状态转移方程中的 m a x max max改成 s u m sum sum即可。例如若每件物品均是完全背包中的物品,转移方程即为
F [ i , v ] = s u m { F [ i − 1 , v ] , F [ i , v − C i ] } F[i,v] = sum\{F[i−1,v],F[i,v−C_i]\} F[i,v]=sum{F[i1,v],F[i,vCi]}

初始条件是 F [ 0 , 0 ] = 1 F[0,0] = 1 F[0,0]=1

F[0][0] = 1;
for (int i = 1; i <= n; ++i) {
	for (int v = 0; v <= V; ++v) {
		if (v >= c[i]) F[i][v] = F[i-1][v] + F[i-1][v-c[i]];
		else F[i][v] = F[i-1][v];
	}
}
ans = F[n][V];
printf("%d\n", ans); 

3.求装得尽量满

再看一题:装箱问题 [NOIp2001普及组第4题]
其实这里 W i W_i Wi就是 C i C_i Ci

memset(F, 0, sizeof(F));
for (int i = 1; i <= n; ++i) {
	for (int v = V; v >= c[i]; --v) {
		F[v] = max(F[v], F[v-c[i]] + c[i]);
	}
}
for (int i = 0; i <= V; ++i) ans = max(ans, F[i]);
printf("%d\n", V - ans);

4.求所有体积可能

又来一题:积木城堡
求出每个高度的城堡数量。

for (int i = 0; i < n; ++i) {
	int np = 0;
	int now;
	int sum = 0;
	while (1) {
		scanf("%d", &now);
		if (now == -1) break;
		a[++np] = now;
		sum += now;
	}
	if (max_sum < sum) max_sum = sum;
	memset(F, 0, sizeof(F));
	F[0] = 1;
	for (int j = 1; j <= np; ++j) {
		for (int v = sum; v >= a[j]; --v) {
			if (F[v-a[j]] && !F[v]) {
				++h[v];
				F[v] = 1;
			}
		}
	}
}

你可能感兴趣的:(算法,动态规划)