This commit is contained in:
estomm
2021-04-01 19:28:38 +08:00
parent 52737674c2
commit 3926b604c9
11 changed files with 208 additions and 72 deletions

View File

@@ -108,7 +108,7 @@ $$
* 树形动态规划。非线性规模增长。非线性决策过程。第二个规模增长方向构成该阶段的状态集合每个阶段的状态并非一个但是每个阶段的状态数量不确定。例如三角形数组最小路径和、单向最短路径问题。时间复杂度为O(n*m)//m表示某一阶段最大的状态数量。
* 矩阵动态规划。非线性规模增长。非线性决策。第二个规模增长方向与第一个规模增长方向独立不受第一个规模增长影响每个阶段的状态数量是固定的。例如背包问题、n个骰子的点数问题。O(n*m)。由于矩阵可以用来表示图。也可以定义为图型动态规划
* 序列动态规划。非线性规模增长。非线性决策。第二个规模增长的方向不受第一个规模增长的影响矩阵动态规划的特殊形式针对序列的动态规划。例如最长公共子序列、正则表达式匹配。O(n*m)
* 二维规模增长的冬天规划,第一维表示的行,第二维表示列。第一维为主要的规模增长方向,第二维是第一维某一阶段的状态集合。
## 4.1 线性动态规划
## 4.2 树型动态规划

View File

@@ -3,6 +3,8 @@
> 矩阵可以看作是图的一种,怎么说?你可以把整个矩阵当成一个图,矩阵里面的每个位置上的元素当成是图上的节点,然后每个节点的邻居就是其相邻的上下左右的位置
>
> 矩阵类动态规划的两个规模增长方向可能存在两种情况:等价独立和非等价独立。例如不同路径和最大矩形中的规模增长方向,是等价独立的,两个规模增长的含义是一样的,比较好判断。但是在背包问题等其他子问题中。规模增长的方向是不等价,一个是背包容量的增长,另一个是物品数量的增长,通常比较难发现。
>
> 在矩阵动态规划中,两个维度的增长方向是可以相互交换的。只要设计好即可。但有可能存在一个简单一个复杂的情况。
> * 不同路径
> * 最大矩形

View File

@@ -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)
### 算法实现

View File

@@ -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 多重背包

View File

@@ -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<iostream>
using namespace std;
#include <algorithm>
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<iostream>
using namespace std;
#include <algorithm>
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种物品每种物品有无限多个第ii从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种物品第ii从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}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB