一、前言:什么是背包问题?
核心本质:你有一个容量有限的背包,面前有一堆宝物,每个宝物都有体积和价值。你的目标是:在不撑破背包的前提下,让带走的宝物总价值最高。
01 的含义:每个物品只有一件。对于每个物品,你只有两个选择:要么选 (1),要么不选 (0)。这就是 01 背包的由来。
二、01 背包:标准模板与两种形态
2.1 题目描述
描述: 你有一个容量为 V 的背包,有 n 个物品。第 i 个物品体积为 v_i,价值为 w_i。 第一问:至多能装多大价值?(不一定装满) 第二问:恰好装满时,至多能装多大价值?(无解输出 0)
示例:3 件物品,容积 5。物品:(2, 10), (4, 5), (1, 4)。 第一问:14(选第 1 和第 3 件);第二问:9(选第 2 和第 3 件)。
2.2 深度拆解(第一问:不超过 V)
1. 状态表示
dp[i][j] 表示:从前 i 件物品中选,总体积不超过 j 的最大价值。
2. 状态转移方程
对于第 i 件物品(体积 v_i,价值 w_i),我们有两种选择:
- 不选它:最大价值等于'前
i-1件物品,体积不超过j'时的价值。dp[i][j] = dp[i-1][j] - 选它:前提是背包得装得下(j >= v_i)。最大价值等于'第
i件的价值'加上'前i-1件物品,剩余空间 j - v_i'时的最大价值。dp[i][j] = dp[i-1][j - v_i] + w_i
综合方程:
dp[i][j] = max(dp[i-1][j], dp[i-1][j - v_i] + w_i)
3. 朴素二维代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, V;
int v[N], w[N];
int dp[N][N]; // 二维数组
int main() {
cin >> n >> V;
for (int i = 1; i <= n; i++) cin >> v[i] >> w[i];
( i = ; i <= n; i++) {
( j = ; j <= V; j++) {
dp[i][j] = dp[i][j];
(j >= v[i]) dp[i][j] = (dp[i][j], dp[i][j - v[i]] + w[i]);
}
}
cout << dp[n][V] << endl;
( j = ; j <= V; j++) dp[][j] = ;
dp[][] = ;
( i = ; i <= n; i++) {
( j = ; j <= V; j++) {
dp[i][j] = dp[i][j];
(j >= v[i] && dp[i][j - v[i]] != )
dp[i][j] = (dp[i][j], dp[i][j - v[i]] + w[i]);
}
}
cout << (dp[n][V] < ? : dp[n][V]) << endl;
;
}


