diff --git a/算法/A类:基本算法/5 动态规划.md b/算法/A类:基本算法/5 动态规划.md index 7e6c6065..d0669566 100644 --- a/算法/A类:基本算法/5 动态规划.md +++ b/算法/A类:基本算法/5 动态规划.md @@ -108,7 +108,7 @@ $$ * 树形动态规划。非线性规模增长。非线性决策过程。第二个规模增长方向构成该阶段的状态集合(每个阶段的状态并非一个),但是每个阶段的状态数量不确定。例如:三角形数组最小路径和、单向最短路径问题。时间复杂度为O(n*m)//m表示某一阶段最大的状态数量。 * 矩阵动态规划。非线性规模增长。非线性决策。第二个规模增长方向与第一个规模增长方向独立,不受第一个规模增长影响,每个阶段的状态数量是固定的。例如背包问题、n个骰子的点数问题。O(n*m)。由于矩阵可以用来表示图。也可以定义为图型动态规划 * 序列动态规划。非线性规模增长。非线性决策。第二个规模增长的方向不受第一个规模增长的影响,矩阵动态规划的特殊形式,针对序列的动态规划。例如:最长公共子序列、正则表达式匹配。O(n*m) - +* 二维规模增长的冬天规划,第一维表示的行,第二维表示列。第一维为主要的规模增长方向,第二维是第一维某一阶段的状态集合。 ## 4.1 线性动态规划 ## 4.2 树型动态规划 diff --git a/算法/A类:基本算法/5 动态规划——矩阵动态规划.md b/算法/A类:基本算法/5 动态规划——矩阵动态规划.md index 9bd4c59c..35a2ebbb 100644 --- a/算法/A类:基本算法/5 动态规划——矩阵动态规划.md +++ b/算法/A类:基本算法/5 动态规划——矩阵动态规划.md @@ -3,6 +3,8 @@ > 矩阵可以看作是图的一种,怎么说?你可以把整个矩阵当成一个图,矩阵里面的每个位置上的元素当成是图上的节点,然后每个节点的邻居就是其相邻的上下左右的位置 > > 矩阵类动态规划的两个规模增长方向可能存在两种情况:等价独立和非等价独立。例如不同路径和最大矩形中的规模增长方向,是等价独立的,两个规模增长的含义是一样的,比较好判断。但是在背包问题等其他子问题中。规模增长的方向是不等价,一个是背包容量的增长,另一个是物品数量的增长,通常比较难发现。 +> +> 在矩阵动态规划中,两个维度的增长方向是可以相互交换的。只要设计好即可。但有可能存在一个简单一个复杂的情况。 > * 不同路径 > * 最大矩形 diff --git a/算法/A类:基本算法/5.11 最优二叉搜索树问题.md b/算法/A类:基本算法/5.11 最优二叉搜索树问题.md deleted file mode 100644 index e69de29b..00000000 diff --git a/算法/A类:基本算法/5.8 投资问题.md b/算法/A类:基本算法/5.8 投资问题.md index e69de29b..73d37ec5 100644 --- a/算法/A类:基本算法/5.8 投资问题.md +++ b/算法/A类:基本算法/5.8 投资问题.md @@ -0,0 +1,29 @@ +## 投资问题 + + +### 问题描述 + +m元钱,n个项目。f_i(x)表示x元钱投入项目i的效益。求最大效益。 + +![](image/2021-04-01-15-01-49.png) + + +### 问题分析 + + +### 算法设计 + +* 问题分解划分阶段:规模增长的方向有两个。第一个是投资的金额想,第二个是项目选择k。x,k阶段。 +* 确定状态变量dp[x][k]表示投资x,第k个项目的最大收益。 +* 确定状态转移方程。 + + +![](image/2021-04-01-15-06-07.png) +* 状态转移过程。 + +![](image/2021-04-01-15-06-19.png) +### 算法效率 + +* O(n*m^2) + +### 算法实现 \ No newline at end of file diff --git a/算法/A类:基本算法/5.9 01背包问题.md b/算法/A类:基本算法/5.9 01背包问题.md deleted file mode 100644 index e7a5de2b..00000000 --- a/算法/A类:基本算法/5.9 01背包问题.md +++ /dev/null @@ -1,71 +0,0 @@ -# 背包问题 -## 1 01 背包问题 - -### 问题描述 -有m个物品,它们有各自的体积和价值,现有给定容量的背包c,如何让背包里装入的物品具有最大的价值总和? - -### 问题分析 - -### 策略选择 - - -### 算法设计 -* 问题分解划分阶段:2个规模增长方向。背包的容量和物品。背包的容量表示为c=1,2,3,n。物品的重量表示为w1,w2,w3。物品的机制v1,v2,v3。第一个阶段表示是否添加物品。第二个阶段是背包容量的增长。 -* 确定状态dp[c,m] -* 确定状态转移方程 - -$$ -dp[c,m]=max(dp[c-1],v[m]+dp[c-w[m]]) -$$ - -### 算法分析 - -### 算法实现 - -``` -for(int i=1;i<=n;i++) -{ - for(int j=v;j>=weight[i];j--) - { - dp[j]=max(dp[j],dp[i-weight[i]]+value[i]); - } -} -``` - -## 2 完全背包问题 - -### 问题描述 - - -### 问题分析 - - -### 策略选择 - - -### 算法设计 - -* 问题分解划分阶段:2个规模增长方向。背包的容量和物品。背包的容量表示为c=1,2,3,n。物品的重量表示为w1,w2,w3。物品的机制v1,v2,v3。第一个阶段表示是否添加物品。第二个阶段是背包容量的增长。 -* 确定状态dp[c,m] -* 确定状态转移方程 - -$$ -dp[i][j]=max(dp[i][j],dp[i-1][j-k*weight[i]]+k*value[i]); -$$ -* 确定边界 -### 算法分析 - - -### 算法实现 -``` - -for(i=1;i<=n;i++) -{ - for(j=weight[i];j<=v;j++) - { - dp[j]=max(dp[j],dp[j-weight[i]]+value[i]); - } -} -``` - -## 3 多重背包 \ No newline at end of file diff --git a/算法/A类:基本算法/5.9 背包问题.md b/算法/A类:基本算法/5.9 背包问题.md new file mode 100644 index 00000000..73c567d0 --- /dev/null +++ b/算法/A类:基本算法/5.9 背包问题.md @@ -0,0 +1,176 @@ +# 背包问题 +## 1 01 背包问题 + +### 问题描述 +有N个物品,它们有各自的体积和价值,现有给定容量的背包c,如何让背包里装入的物品具有最大的价值总和? + +N=4 +i 1,2,3,4 +w 2,3,4,5 +v 3,4,5,6 +c=8 + +### 问题分析 + +### 策略选择 + + +### 算法设计 +有两种动态规划的思路,本质上是一致的。背包的容量增长作为第一维,或者物品的数量增长作为第一维。 + +* 当背包的容量作为第一维的时候。背包容量为行,物品增长为列。 + * 问题分解划分阶段。背包容量容量为i,物品选择为j + * 确定状态dp[i][j]表示背包容量为i的情况下,第j个物品放入或者不放入的最大价值。 + * 确定状态转移方程。分两种情况讨论。当背包容量为i时,第j个物品放入和第j个物品不放入。 + +$$ +dp[i][j]=max(dp[i][j-1],dp[i-w[i]][j-1]) +$$ + + +* 当物品的增长作为第一维的时候。物品增长为行,背包容量为列 +![](image/2021-04-01-14-37-22.png) + * 问题分解划分阶段:2个规模增长方向。背包的容量和物品。物品选择i。背包的容量表示为j。第一个阶段表示是否添加物品。第二个阶段是背包容量的增长。 + * 确定状态dp[i][j]表示第i个物品,在背包容量j的情况下的最大价值。 + * 确定状态转移方程 + +$$ +dp[i][j]=max(dp[i-1][j],v[i]+dp[i-1][j-w[i]]) +$$ + +> 两种计算方式完全一致。 + +### 算法分析 + +### 算法实现 +```C++ +#include +using namespace std; +#include + +int main() +{ + int w[5] = { 0 , 2 , 3 , 4 , 5 }; //商品的体积2、3、4、5 + int v[5] = { 0 , 3 , 4 , 5 , 6 }; //商品的价值3、4、5、6 + int bagV = 8; //背包大小 + int dp[5][9] = { { 0 } }; //动态规划表 + + for (int i = 1; i <= 4; i++) { + for (int j = 1; j <= bagV; j++) { + if (j < w[i]) + dp[i][j] = dp[i - 1][j]; + else + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); + } + } + + //动态规划表的输出 + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 9; j++) { + cout << dp[i][j] << ' '; + } + cout << endl; + } + + return 0; +} +``` + +最优的背包价值路径回溯方法 +![](image/2021-04-01-14-43-16.png) +```C++ +#include +using namespace std; +#include + +int w[5] = { 0 , 2 , 3 , 4 , 5 }; //商品的体积2、3、4、5 +int v[5] = { 0 , 3 , 4 , 5 , 6 }; //商品的价值3、4、5、6 +int bagV = 8; //背包大小 +int dp[5][9] = { { 0 } }; //动态规划表 +int item[5]; //最优解情况 + +void findMax() { //动态规划 + for (int i = 1; i <= 4; i++) { + for (int j = 1; j <= bagV; j++) { + if (j < w[i]) + dp[i][j] = dp[i - 1][j]; + else + dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]); + } + } +} + +void findWhat(int i, int j) { //最优解情况 + if (i >= 0) { + if (dp[i][j] == dp[i - 1][j]) { + item[i] = 0; + findWhat(i - 1, j); + } + else if (j - w[i] >= 0 && dp[i][j] == dp[i - 1][j - w[i]] + v[i]) { + item[i] = 1; + findWhat(i - 1, j - w[i]); + } + } +} + +void print() { + for (int i = 0; i < 5; i++) { //动态规划表输出 + for (int j = 0; j < 9; j++) { + cout << dp[i][j] << ' '; + } + cout << endl; + } + cout << endl; + + for (int i = 0; i < 5; i++) //最优解输出 + cout << item[i] << ' '; + cout << endl; +} + +int main() +{ + findMax(); + findWhat(4, 8); + print(); + + return 0; +} +``` + +## 2 完全背包问题 + +### 问题描述 + +完全背包(unbounded knapsack problem)与01背包不同就是每种物品可以有无限多个:一共有N种物品,每种物品有无限多个,第i(i从1开始)种物品的重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少? + +### 问题分析 + + +### 策略选择 + + +### 算法设计 + +* 问题分解划分阶段:2个规模增长方向。背包的容量和物品。背包的个数增长i=1,2,3,n。背包容量为j。第一个阶段表示是否添加物品。第二个阶段是背包容量的增长。 +* 确定状态dp[i,j] +* 确定状态转移方程 + +$$ +dp[i][j] = max{(dp[i-1][j − k*w[i]] + k*v[i]) for every k} +$$ +* 确定边界 +### 算法分析 + + +### 算法实现 + + +## 3 多重背包 + + +### 问题描述 +多重背包(bounded knapsack problem)与前面不同就是每种物品是有限个:一共有N种物品,第i(i从1开始)种物品的数量为n[i],重量为w[i],价值为v[i]。在总重量不超过背包承载上限W的情况下,能够装入背包的最大价值是多少? +### 算法设计 +``` +dp[i][j] = max{(dp[i-1][j − k*w[i]] + k*v[i]) for every k} +``` \ No newline at end of file diff --git a/算法/A类:基本算法/image/2021-04-01-14-37-22.png b/算法/A类:基本算法/image/2021-04-01-14-37-22.png new file mode 100644 index 00000000..4bb4969c Binary files /dev/null and b/算法/A类:基本算法/image/2021-04-01-14-37-22.png differ diff --git a/算法/A类:基本算法/image/2021-04-01-14-43-16.png b/算法/A类:基本算法/image/2021-04-01-14-43-16.png new file mode 100644 index 00000000..f4f891ff Binary files /dev/null and b/算法/A类:基本算法/image/2021-04-01-14-43-16.png differ diff --git a/算法/A类:基本算法/image/2021-04-01-15-01-49.png b/算法/A类:基本算法/image/2021-04-01-15-01-49.png new file mode 100644 index 00000000..8fa58629 Binary files /dev/null and b/算法/A类:基本算法/image/2021-04-01-15-01-49.png differ diff --git a/算法/A类:基本算法/image/2021-04-01-15-06-07.png b/算法/A类:基本算法/image/2021-04-01-15-06-07.png new file mode 100644 index 00000000..8b9b7ea6 Binary files /dev/null and b/算法/A类:基本算法/image/2021-04-01-15-06-07.png differ diff --git a/算法/A类:基本算法/image/2021-04-01-15-06-19.png b/算法/A类:基本算法/image/2021-04-01-15-06-19.png new file mode 100644 index 00000000..3130026d Binary files /dev/null and b/算法/A类:基本算法/image/2021-04-01-15-06-19.png differ