一、0 / 1背包问题简介
0/1背包问题是动态规划中最经典的问题,没有之一。
背包问题: 有若干个物品,可能体积或重量,价值不同,和一个容量有限的背包,问如何选择物品才能使得背包里装的物品价值最大。
可能有些小伙伴会产生疑惑,这问题用贪心法求解不就行了。把价值最大,体积或质量最小的物品收入背包。嗯嗯…………这样想倒也没错,但是这个背包问题的在于直接判断价值 val 和 体积/质量 vol (暂且定为vol,质量或体积视题目情况而定)之间的关系并不一定是最优解,例如:在放入价值第1大的物品后,背包的剩余容积已经放不下价值第2大的物品,。但是价值第3大的物品却能放进去,或者价值第1大的物品体积也是第1大,根本放不了背包,反而是第3大价值和第4大价值和最低价值的物品能够放进背包。
二、分析背包
1.背包模型建立
首先我们要确立一点,物品的状体只有 2 种。要么装进背包,要么不装进背包。
x i = 0 o r 1 ( i = 1 , 2 , 3... n ) x_i= 0\:or \:1 \;\;( i = 1,2,3...n) xi=0or1(i=1,2,3...n)
这里我们利用一个二维数组对背包的状态进行存储。
const int N = 1009;
int dp[N][N],n,m,e[N],v[N]; // n,m分别为物品数量和物品体积
其中 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示的是装入第 i i i 个物品时,此时背包的容积为 j j j , d p [ i ] [ j ] dp[i][j] dp[i][j] 存储着背包总价值。对于任意的 d p [ i ] [ j ] dp[i][j] dp[i][j] 满足 0 ≤ i ≤ n , 0 ≤ j ≤ m 0 \leq i \leq n,0 \leq j \leq m\; 0≤i≤n,0≤j≤m。如果我们选择将物品 x i x_i xi 放入背包中且 j ≥ e [ i ] j \geq e[i] j≥e[i] 。 d p [ i ] [ j ] = d p [ i − 1 ] [ j − v [ i ] ] + e [ i ] dp[i][j] = dp[i - 1][j - v[i]] + e[i] dp[i][j]=dp[i−1][j−v[i]]+e[i] 。如果我们选择不放入 x i x_i xi 物品,或者 j < e [ i ] , d p [ i ] [ j ] = d p [ i − 1 ] [ j ] j < e[i],dp[i][j] = dp[i - 1][j] j<e[i],dp[i][j]=dp[i−1][j] 。为了使得背包内的价值最大 d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − v [ i ] ] + e [ i ] ) dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - v[i]] + e[i]) dp[i][j]=max(dp[i−1][j],dp[i−1][j−v[i]]+e[i])
2.题目演练
有
n
n
n 件物品和一个容量是
m
m
m 的背包。每件物品只能使用一次。
第
i
i
i 件物品的价值是
e
i
e_i
ei ,体积是
v
i
v_i
vi 。
将哪些物品装入背包,可使得这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值
W
W
W。
输入格式
第一行两个整数,
N
N
N,
V
V
V,用空格隔开,分别表示物品数量和背包容积。
接下来有 N N N 行,每行两个整数 v i , e i v_i,e_i vi,ei,用空格隔开,分别表示第 i i i 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0
<
N
,
V
≤
1000
0<N,V≤1000
0<N,V≤1000
0 < v i , w i ≤ 1000 0<vi,wi≤1000 0<vi,wi≤1000
代码如下
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1009;
int dp[N][N],n,m,e[N],v[N];
signed main(){
// 取消同步
ios::sync_with_stdio(false);
cin.tie(nullptr);
// 输入物品数量和背包体积
cin >> n >> m;
// 读取每件物品的体积和价值
for(int i = 1 ; i <= n ; i++) cin >> v[i] >> e[i];
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= m ; j++)
// 当前背包容量是否可以装下 xi
if(j >= v[i]) dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - v[i]] + e[i]);
else dp[i][j] = dp[i - 1][j];
}
cout << dp[n][m] << endl;
return 0;
}
总结
0/1背包问题真的不是很难,多看多记!!!