diff --git a/README.md b/README.md index bf55a004..b43fa38c 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ * 编程语言 * [C++面试&C++学习指南知识点整理](https://github.com/youngyangyang04/TechCPP) + * [C++语言基础课](https://kamacoder.com/course.php?course_id=1) * 项目 * [基于跳表的轻量级KV存储引擎](https://github.com/youngyangyang04/Skiplist-CPP) diff --git a/problems/周总结/20201107回溯周末总结.md b/problems/周总结/20201107回溯周末总结.md index 9a447648..2d20a197 100644 --- a/problems/周总结/20201107回溯周末总结.md +++ b/problems/周总结/20201107回溯周末总结.md @@ -31,7 +31,7 @@ for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; 在[回溯算法:求组合总和(二)](https://programmercarl.com/0039.组合总和.html)第一个树形结构没有画出startIndex的作用,**这里这里纠正一下,准确的树形结构如图所示:** -![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201123202227835.png) +![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170730367.png) ## 周二 diff --git a/problems/回溯总结.md b/problems/回溯总结.md index 35b4c3f9..5d4c9450 100644 --- a/problems/回溯总结.md +++ b/problems/回溯总结.md @@ -116,8 +116,8 @@ void backtracking(参数) { **注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路**。 树形结构如下: +![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201223170730367.png) -![39.组合总和](https://code-thinking-1253855093.file.myqcloud.com/pics/20201118152521990.png) 最后还给出了本题的剪枝优化,如下: diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 79ad26a8..bc5f2e5d 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -8,6 +8,9 @@ # 动态规划:01背包理论基础 + +本题力扣上没有原题,大家可以去[卡码网第46题](https://kamacoder.com/problem.php?id=1046)去练习,题意是一样的。 + ## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[带你学透0-1背包问题!](https://www.bilibili.com/video/BV1cg411g7Y6/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 @@ -261,6 +264,55 @@ int main() { ``` +本题力扣上没有原题,大家可以去[卡码网第46题](https://kamacoder.com/problem.php?id=1046)去练习,题意是一样的,代码如下: + +```CPP + +//二维dp数组实现 +#include +using namespace std; + +int n, bagweight;// bagweight代表行李箱空间 +void solve() { + vector weight(n, 0); // 存储每件物品所占空间 + vector value(n, 0); // 存储每件物品价值 + for(int i = 0; i < n; ++i) { + cin >> weight[i]; + } + for(int j = 0; j < n; ++j) { + cin >> value[j]; + } + // dp数组, dp[i][j]代表行李箱空间为j的情况下,从下标为[0, i]的物品里面任意取,能达到的最大价值 + vector> dp(weight.size(), vector(bagweight + 1, 0)); + + // 初始化, 因为需要用到dp[i - 1]的值 + // j < weight[0]已在上方被初始化为0 + // j >= weight[0]的值就初始化为value[0] + for (int j = weight[0]; j <= bagweight; j++) { + dp[0][j] = value[0]; + } + + for(int i = 1; i < weight.size(); i++) { // 遍历科研物品 + for(int j = 0; j <= bagweight; j++) { // 遍历行李箱容量 + // 如果装不下这个物品,那么就继承dp[i - 1][j]的值 + if (j < weight[i]) dp[i][j] = dp[i - 1][j]; + // 如果能装下,就将值更新为 不装这个物品的最大值 和 装这个物品的最大值 中的 最大值 + // 装这个物品的最大值由容量为j - weight[i]的包任意放入序号为[0, i - 1]的最大值 + 该物品的价值构成 + else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); + } + } + cout << dp[weight.size() - 1][bagweight] << endl; +} + +int main() { + while(cin >> n >> bagweight) { + solve(); + } + return 0; +} + +``` + ## 总结 diff --git a/problems/背包理论基础01背包-2.md b/problems/背包理论基础01背包-2.md index f60e261b..3e2134b4 100644 --- a/problems/背包理论基础01背包-2.md +++ b/problems/背包理论基础01背包-2.md @@ -6,6 +6,7 @@ # 动态规划:01背包理论基础(滚动数组) +本题力扣上没有原题,大家可以去[卡码网第46题](https://kamacoder.com/problem.php?id=1046)去练习 ## 算法公开课 @@ -13,7 +14,6 @@ ## 思路 - 昨天[动态规划:关于01背包问题,你该了解这些!](https://programmercarl.com/背包理论基础01背包-1.html)中是用二维dp数组来讲解01背包。 今天我们就来说一说滚动数组,其实在前面的题目中我们已经用到过滚动数组了,就是把二维dp降为一维dp,一些录友当时还表示比较困惑。 @@ -159,6 +159,8 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15 +C++代码如下: + ```CPP void test_1_wei_bag_problem() { vector weight = {1, 3, 4}; @@ -181,6 +183,49 @@ int main() { ``` +本题力扣上没有原题,大家可以去[卡码网第46题](https://kamacoder.com/problem.php?id=1046)去练习,题意是一样的,代码如下: + +```CPP +// 一维dp数组实现 +#include +#include +using namespace std; + +int main() { + // 读取 M 和 N + int M, N; + cin >> M >> N; + + vector costs(M); + vector values(M); + + for (int i = 0; i < M; i++) { + cin >> costs[i]; + } + for (int j = 0; j < M; j++) { + cin >> values[j]; + } + + // 创建一个动态规划数组dp,初始值为0 + vector dp(N + 1, 0); + + // 外层循环遍历每个类型的研究材料 + for (int i = 0; i < M; ++i) { + // 内层循环从 N 空间逐渐减少到当前研究材料所占空间 + for (int j = N; j >= costs[i]; --j) { + // 考虑当前研究材料选择和不选择的情况,选择最大值 + dp[j] = max(dp[j], dp[j - costs[i]] + values[i]); + } + } + + // 输出dp[N],即在给定 N 行李空间可以携带的研究材料最大价值 + cout << dp[N] << endl; + + return 0; +} + +``` + 可以看出,一维dp 的01背包,要比二维简洁的多! 初始化 和 遍历顺序相对简单了。 **所以我倾向于使用一维dp数组的写法,比较直观简洁,而且空间复杂度还降了一个数量级!** diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index a006cb0e..a173c6dd 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -7,6 +7,8 @@ # 动态规划:完全背包理论基础 +本题力扣上没有原题,大家可以去[卡码网第52题](https://kamacoder.com/problem.php?id=1046)去练习,题意是一样的。 + ## 算法公开课 **[《代码随想录》算法视频公开课](https://programmercarl.com/other/gongkaike.html):[带你学透完全背包问题! ](https://www.bilibili.com/video/BV1uK411o7c9/),相信结合视频再看本篇题解,更有助于大家对本题的理解**。 @@ -162,6 +164,43 @@ int main() { ``` +本题力扣上没有原题,大家可以去[卡码网第46题](https://kamacoder.com/problem.php?id=1046)去练习,题意是一样的,C++代码如下: + +```cpp +#include +#include +using namespace std; + +// 先遍历背包,再遍历物品 +void test_CompletePack(vector weight, vector value, int bagWeight) { + + vector dp(bagWeight + 1, 0); + + for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量 + for(int i = 0; i < weight.size(); i++) { // 遍历物品 + if (j - weight[i] >= 0) dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); + } + } + cout << dp[bagWeight] << endl; +} +int main() { + int N, V; + cin >> N >> V; + vector weight; + vector value; + for (int i = 0; i < N; i++) { + int w; + int v; + cin >> w >> v; + weight.push_back(w); + value.push_back(v); + } + test_CompletePack(weight, value, V); + return 0; +} +``` + + ## 总结