您的位置:首页 > 其它

慕课玩转算法课程之动态规划入门——1

2017-08-18 10:34 295 查看
动态规划:将原问题转化为许多子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。

实际上,动态规划本质上都是递归问题,但是其中会有重叠子问题求解的现象。对于重叠子问题的求解方式,有两种,分别是记忆化搜索(自顶向下的解决问题,思考容易),另一个就是动态规划的方式(自底向上的解决问题,一般还是从记忆化搜索的方式思考,然后自底向上的解决,代码更简洁)。

本节只讨论能明显的发现重复子问题的动态规划问题。

1. 斐波那契数列

自顶向下的分析:要求f(n),需要知道f(n-1)和f(n-2),可知子问题的形式。

记忆化搜素,自顶向下的思考,先找到大问题,再分解为子问题,保存子问题的解。
vector<int> memo;

// 记忆化搜索
int fib( int n ){

if( n == 0 )
return 0;

if( n == 1 )
return 1;

if( memo
== -1 )
memo
= fib(n-1) + fib(n-2);

return memo
;
}

int main() {

int n = 1000;
memo = vector<int>(n+1,-1);//初始化为全-1的向量,保证里面乜有任何斐波数。

time_t startTime = clock();//记录运行时间
int res = fib(n);
time_t endTime = clock();

cout<<"fib("<<n<<") = "<<res<<endl;
cout<<"time : "<<double(endTime-startTime)/CLOCKS_PER_SEC<<" s"<<endl;

return 0;
}


动态规划,自底向上解题
// 动态规划
int fib( int n ){

vector<int> memo(n+1, -1);

memo[0] = 0;
memo[1] = 1;
for( int i = 2 ; i <= n ; i ++ )
memo[i] = memo[i-1] + memo[i-2];

return memo
;
}

2. 爬楼梯问题

n阶楼梯,每次爬一层或两层求问有多少种爬楼梯方法。
自顶向下的分析:



普通递归
class Solution {
private:
vector<int> memo;

int calcWays(int n){

if( n == 1)
return 1;
if (n == 2)
return 2;

return calcWays(n - 1) + calcWays(n - 2);
}
public:
int climbStairs(int n) {
return calcWays(n);
}
};


普通递归同样存在重复求解的情况,考虑记忆化搜索的方式
// 记忆化搜索
class Solution {
private:
vector<int> memo;

int calcWays(int n){

if( n == 1)
return 1;
if (n == 2)
return 2;

if( memo
== -1 ) //在上面的调用递归函数的之前,判断memo中是否有值,没有,则把递归调用的结果存在memo
中
memo
= calcWays(n-1) + calcWays(n-2);

return memo
;
}
public:
int climbStairs(int n) {

memo = vector<int>(n+1,-1);
return calcWays(n);
}
};


动态规划解法
class Solution {
//已经不需要递归函数
public:
int climbStairs(int n) {

vector<int> memo(n + 1, -1);
memo[1] = 1;
memo[2] = 2;
for (int i = 3; i <= n; i++)
memo[i] = memo[i - 1] + memo[i - 2];
return memo
;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
cout << Solution().climbStairs(10) << endl;  //89
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: