动态规划(英语:Dynamic programming,简称 DP),通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。(dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems.)
一般这些子问题很相似,可以通过函数关系式递推出来这个相似的子问题的结构。然后动态规划就致力于使每个子问题只被解决一次,减少重复计算,比如斐波那契数列就可以看做入门级的经典动态规划问题。所以动态规划的核心思想就是拆分出重复子问题,记忆答案,减少重复计算。
动态规划的本质是一个状态机,从初始状态开始进行有向无环的跳转,最终求得最终解。状态转移方程完美诠释了状态机中状态跳转的概念
示例:M级超级台阶
程序展示(自底向上递推)
#include "iostream"
using namespace std;
int n;
int m,dp[3];
int main(){
cin>>n;
for (int i = 1; i <=n ; ++i) {
cin>>m;
dp[0] = dp[1] = 1;
if(m<2){
break;
}
for(int j=2;j<m;j++){
dp[j%3] = dp[(j-1)%3]+dp[(j-2)%3];//这里使用滚动数组来优化空间
}
cout<<dp[(m-1)%3]<<endl;
}
return 0;
}
程序展示(自顶向下记忆话搜索)
#include "iostream"
using namespace std;
int n;
int m,dp[41];
int dfs(int n);
int main(){
cin>>n;
for (int i = 1; i <=n ; ++i) {
cin>>m;
cout<<dfs(m)<<endl;
}
return 0;
}
int dfs(int n){
if(n == 1||n == 2){
return 1;
}
if(dp[n]){
return dp[n];
}
dp[n] = dfs(n-1) + dfs(n-2);
return dp[n];
}