动态规划——总结
Posted 牧空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划——总结相关的知识,希望对你有一定的参考价值。
动态规划的核心思想就是存储之前操作的结果
适用的情况如下:
- 最优子结构性质。问题的最优解包含的子问题的解也是最优的,那么称该问题具有最优子结构性质。
- 无后效性。即子问题的解一旦确定,就不再改变,不受之后、包含它的问题的求解决策影响
- 子问题重叠性质。也就是有些子问题会被重复计算多次,动态规划就是利用这个性质,对每个子问题值计算一次。其余只需要进行查表即可
一般有如下步骤
- 问题拆分,找到问题之间的联系
- 确定状态构成
- 确定状态转换方程
- 实现
在问题拆分的过程中我们会涉及到一个或多个变量来表示当前所处的是哪个子问题,通常这些变量加上当前子问题的解就构成了我们所需的状态。
可以再举一个栗子:
有一个数字三角形如下,问自顶向下哪条路径上数字和最大
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
- 最初步的想法就是从顶层到第
i
层的最大路径和,但是显而易见的是这样会存在一个问题,没法把限制条件每步只能沿对角线向坐下或右下滑动体现在状态转换中 - 在上述基础上加上一个变量来满足限制条件,将问题拆分成从顶层到达第
i
层第j
个数字的路径的最大和,即dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+matrix[i][j]
,matrix[i][j]
表示三角形中各个位置的数值,那么问题的解就是从max(dp[n])
,n为层数。同时也要加上一个限制条件防止下标溢出,即左右边界只能向内侧滑动 - 换一种思路,从下向上计算,
dp[i][j]
表示从(i,j)点出发到底部路径所有值之和的最大值,则dp[0][0]
就是问题的答案。状态转换方程为dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+matrix[i][j]
,当然是逆序遍历i
的所有值
对上述思路二三进行实现
思路二
#include <iostream>
#include <cstdio>
#include <cstring>
#define MAXN 100
using namespace std;
int main(int argc, char const *argv[])
{
int n; //层数
scanf("%d", &n);
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &dp[i][j]);
for (int i = 1; i < n; i++)
{
for (int j = 0; j <= i; j++)
{
if (j == 0)
dp[i][j] += dp[i - 1][j];
else if (j == i)
dp[i][j] += dp[i - 1][j - 1];
else
dp[i][j] += max(dp[i - 1][j - 1], dp[i - 1][j]);
}
}
int ans;
for (int i = 0; i < n; i++)
ans = max(ans, dp[n - 1][i]);
printf("%d\\n", ans);
return 0;
}
思路三
int main(int argc, char const *argv[])
{
int n; //层数
scanf("%d", &n);
memset(dp, 0, sizeof(dp));
for (int i = 0; i < n; i++){
for (int j = 0; j <= i; j++){
scanf("%d", &matrix[i][j]);
dp[i][j] = matrix[i][j];
}
}
for (int i = n - 1; i >= 0; i--){
for (int j = 0; j <= i; j++){
dp[i][j] += max(dp[i + 1][j], dp[i + 1][j + 1]);
}
}
printf("%d\\n", dp[0][0]);
return 0;
}
以上是关于动态规划——总结的主要内容,如果未能解决你的问题,请参考以下文章