本篇文章主要总和动态规划中常见类型的模板,详细的讲解在每个知识点下的链接中。
目录
入门
动态规划是从暴力dfs慢慢优化出来的算法,以本篇入门了解dp思想,之后再系统学习各类。
递归与递推:
- 递归:自上向下,把问题分解为子问题,直到分解到最下,通过记录子问题的解,来使下次碰到子问题时直接使用之前的记录
- 递推:自底向上,从边界出发,不断向上解决问题
1-背包问题
注意!
- 一维dp中,01背包和多重背包的j是从V~0遍历,完全背包是从0~V
- 存储时都要从1开始,因为涉及到i - 1的处理
01背包:
从01背包开始动态规划:暴力解法 + dp + 滚动数组 + dp优化-CSDN博客
f [ i ] [ j ] 表示在选到第 i 个物品,背包剩余体积为 j 时的最大总价值
二维数组:
for(int i = 1;i <= n;i++){
for(int j = 0;j <= V;j++){
f[i][j] = f[i - 1][j];
if(j >= v[i])
f[i][j] = max(f[i][j],f[i - 1][j - v[i]] + w[i]);
}
}
一维数组:
for(int i = 1;i <= n;i++){
for(int j = V;j >= 0 ;j--){
if(j >= v[i]) {
f[j] = max(f[j],f[j - v[i]] + w[i]);
}
}
}
完全背包:
完全背包的动态规划:暴力dfs + dp + dp优化-CSDN博客
二维数组:
for(int i = 1;i <= n;i++){
for(int j = 0;j <= V;j++){
f[i][j] = f[i - 1][j];
if(j >= v[i])
f[i][j] = max(f[i - 1][j],f[i][j - v[i]] + w[i]);
}
}
一维数组:
for(int i = 1;i <= n;i++){
for(int j = 0;j <= V;j++){
if(j >= v[i])
f[j] = max(f[j],f[j - v[i]] + w[i]);
}
}
多重背包:
多重背包的动态规划:暴力dfs + dp + dp优化-CSDN博客
二维数组:
for(int i = 1;i <= n;i++){
for(int j = 0;j <= V;j++){
f[i][j] = f[i - 1][j];
for(int k = 1;k <= s[i];k++){
if(j >= v[i] * k)
f[i][j] = max(f[i][j],f[i - 1][j - v[i] * k] + w[i] * k);
}
}
}
一维数组:
for(int i = 1;i <= n;i++){
for(int j = V;j >= 0;j--){
for(int k = 1;k <= s[i];k++){
if(j >= v[i] * k)
f[j] = max(f[j],f[j - v[i] * k] + w[i] * k);
}
}
}
2-线性dp
线性dp是指所有的状态转移方程之间存在线性关系,即可以通过计算来求出结果
数字三角形
f[ i ] [ j ]表示到第i行第i列的最大和,本题采用倒序,即从树的最下面开始遍历
二维数组:
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
f[i][j] = max(f[i + 1][j], f[i + 1][j + 1]) + mp[i][j];
}
}
一维数组:
for (int i = n - 1; i >= 0; i--) {
for (int j = 0; j < n; j++) {
f[j] = max(f[j], f[j + 1]) + mp[i][j];
}
}
最长上升子序列 ( LIS )
最长上升子序列的动态规划:暴力dfs + 记忆化搜索 + dp-CSDN博客
f [ i ] 表示以第i个数为结尾,最长的上升子序列个数。然后对i之前的数进行遍历,以此求出f [ i ]
for(int i = 0;i < n;i++){
f[i] = 0;
for(int j = 0;j < i;j++){
if(nums[j] < nums[i])
f[i] = max(f[i],f[j] + 1);
}
res = max(res,f[i]);
}
最长公共子序列(Lcs)
本题有两种状态表示的方法,将其分类为a[ i ] 与 b[ i ] 是否相等更便于理解
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
if(a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1;
else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
}
}
最短编辑距离:
for(int i = 1;i <= n;i++){
for(int j = 1;j <= m;j++){
f[i][j] = min(f[i - 1][j],f[i][j - 1]) + 1;
if(a[i] == b[j]) f[i][j] = min(f[i][j],f[i - 1][j - 1]);
else f[i][j] = min(f[i][j],f[i - 1][j - 1] + 1);
}
}
3-区间动态规划
for(int len = 2;len <= n;len++){
for(int i = 1;i + len - 1 <= n;i++){
int l = i,r = i + len - 1;
f[l][r] = 1e8;
for(int k = l;k < r;k++)
f[l][r] = min(f[l][r],f[l][k] + f[k + 1][r] + s[r] - s[l - 1]);
}
}
以上是本文全部内容,如果对你有帮助点个赞再走吧~ ₍˄·͈༝·͈˄*₎◞ ̑̑