文章目录
1、动态规划(DP)是什么?
2、动态规划模版
3、动态规划例题
1、动态规划(DP)是什么?
动态规划是把一个大问题拆成简单的小问题,通过递推得到(有点像裂项的通项公式)。事实上,动态规划比暴力就好在:不用重复计算同一个值(记忆化搜索)。
动态规划的复杂度=暴力+记忆化搜索
举个例子:
1+1+1+1=4
1+1+1+1+1=5(它等于1+4,就不用再把上一个式子算一次了)
2、动态规划模版
//01背包计数:
for(...) {
for (int j = tmp ; j >= a[i] ; j -- )
f[j] = (f[j] + f[j - a[i]]);
}
//完全背包计数:
for(...) {
for (int j = a[i] ; j <= tmp ; j ++ )
f[j] = (f[j] + f[j - a[i]]);
}
3、动态规划例题
经典题:爬楼梯
有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。
思路1:暴力递归
由于代码简单,此处就不写了
思路2:有思路递归(看出来是斐波那契数列,通项公式为:f(n) = f(n - 1) + f(n - 2))
#include <bits/stdc++.h>
using namespace std;
int climbstair (int n) {
if (n == 1) return 1;
if (n == 2) return 2;//边界条件
return climbstair (n - 1) + climbstair (n - 2); //计算公式,算出每一项
}
int main () {
cout << climbstair (10) << endl;
return 0;
}
刚才的程序有一个问题:复杂度太高。它的复杂度是O(2²),可以看做是一个二叉树。导致这个问题的原因是:重复计算一个数。就比如:计算f(n-2)需要f(n-4),计算f(n-3)也需要f(n-4)。如果用一个数来储存,时间复杂度肯定会降低。这种算法,就叫做记忆化搜索。
思路3:记忆化搜索
#include <bits/stdc++.h>
using namespace std;
vector <int> v;
int climbstair (int n) {
if (n == 1) return 1;
if (n == 2) return 2;//边界条件
if (v[n] != -1) return v[n];//记忆化搜索,如果见过,就直接返回值
v[n] = climbstair (n - 1) + climbstair (n - 2);//否则给它赋值
return v[n];
}
int main () {
v = vector <int> (11 , -1);//将vector数组全定为-1
cout << climbstair (10) << endl;
return 0;
}
现在的程序,时间复杂度已经接近动态规划了。但是,空间复杂度还停留在O(n)。所以,下面出场的,就是我们的动!态!规!划!
思路4:动态规划
由于前面已经推出了通项公式,所以只要用数组模拟就行了
#include <bits/stdc++.h>
using namespace std;
int main () {
int a = 1 , b = 2 , c;//初始赋值
for (int i = 3 ; i <= 10 ; i ++ ) {
c = a + b;
a = c;
b = c;
}//实现公式
cout << c << endl;
return 0;
}
是不是很简短
现在,时间复杂度降为O(n),空间复杂度降为O(1)!!!
这,就是动态规划。
The End…
码字不易,留个评论再走呗!