Day41——动态规划Ⅲ
- 1.理论基础——代码随想录
- 2.纯01背包_[kamacoder46](https://kamacoder.com/problempage.php?pid=1046)
- 3.leetcode_416分割等和子集
背包!!
1.理论基础——代码随想录
主要掌握01背包和完全背包
物品数量: 只有一个 —— 01背包;
无数个 —— 完全背包;
不同物品数量不同 —— 多重背包;
按组打包,每组最多选一个 —— 分组背包;
2.纯01背包_kamacoder46
题目描述:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大
思路:
- 暴力方法:所有物品只有两种状态,装或者不装,因此可以用回溯法搜索所有情况,然后选择
- 二维数组dp01背包:
- dp[i][j]表示容量为 j 的背包从前i件(0=<x<i)物品里随便装所取得的物品最大价值
- 当物品价值最大时,第i件物品如果不在背包里,那么dp[i][j] = dp[i-1][j];
如果在背包里,dp[i][j] = dp[i-1][j-w[i]] + v[i];
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]); - 初始化: 背包容量为0,价值为0;dp[i][0] = 0;
从定义可知,i 从 1开始有意义, i > 0;
补充:当 i= 0 时,因为i>0时,dp[i][j]都与dp[i-1][j]相关,因此需要初始化i= 0;如果 j < w[0],那么不用管,本来就放不进去,但如果 j > w[0],此时的dp[0][j]就需要置为v[0]了,因为第一个能放入背包。 - 顺序:i从1 ~ n,j 从 w ~ 0;
先遍历物品和先遍历物品,都差不多 - dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]);
#include <iostream>#include <vector>using namespace std;int main() {int M, N;cin >> M >> N;vector<vector<int>> item(M, vector<int>(2, 0));for(int i = 0; i < M; i++) {cin >> item[i][0];}for(int i = 0; i < M; i++) {cin >> item[i][1];}vector<vector<int>> dp(M, vector<int>(N + 1, 0));for (int j = item[0][0]; j <= N; j++) {dp[0][j] = item[0][1];}for(int i = 1; i < M; i++) {for(int j = 0; j <= N; j++) {if(item[i][0] > j) dp[i][j] = dp[i-1][j];else dp[i][j] = max(dp[i-1][j], dp[i-1][j-item[i][0]] + item[i][1]);}}cout << dp[M-1][N];return 0;}
方法二:一维数组
dp[i][j] = max(dp[i-1][j], dp[i-1][j-item[i][0]] + item[i][1])
可以用dp[i][j]来保存dp[i-1][j],从而转换成一维数组
dp[j] = max(dp[j], dp[j-w[i]+item[i][1]);
#include <iostream>#include <vector>using namespace std;int main() {int M, N;cin >> M >> N;vector<vector<int>> item(M, vector<int>(2, 0));for(int i = 0; i < M; i++) {cin >> item[i][0];}for(int i = 0; i < M; i++) {cin >> item[i][1];}vector<int> dp(N + 1, 0);for(int i = 0; i < M; i++) {for(int j = N; j >= item[i][0]; j--) {dp[j] = max(dp[j], dp[j-item[i][0]] + item[i][1]);}}cout << dp[N];return 0;}
3.leetcode_416分割等和子集
思路: