动态规划走楼梯_数据结构与算法||第十一节 动态规划

d16bd75566949fad8a955d21adaa399e.png

斐波那契数列

斐波那契数列是这样的一个数列:1,  1,  2,  3,  5,  8,  13,  21,  ...,这个数列从第3个数开始,每个数都等于前面两个数的和。这个数列与大自然中植物的关系极为密切,几乎所有花朵的花瓣都来自这个数列中的一项数字,同时在植物的叶、枝、茎等排列中也存在斐波那契数列。

递归模型:

2523b4eecd17185ea13ce8f3f8b6d870.png

递归实现求第n项:

#includeusing namespace  std;//自定义递归函数,int f(int n){    //递归边界条件当n==1||n==2    if(n==1||n==2){        return 1;    }    //从上向下想求第n项,假设n-1项和n-2项可求,依次向下假设推进    return f(n-1)+f(n-2);}int main(){    int n;    cin>>n;    cout<}

拆解递归过程:

假设输入n的数值为6,递归过程中发现会出现重叠子问题:

13d40c4025d92e893070a45dbe55090d.png

程序验证重叠子问题:

#includeusing namespace  std;int num=0;//定义验证标记int f(int n){    //验证标记num    num++;    if(n==1||n==2){        return 1;    }    return f(n-1)+f(n-2);}int main(){    int n=6;    f(n);    //输出总的调用次数    cout<endl;}

把右半边的递归又重复走了一遍,15次:

94ee9cb2da143312b10758ec00213dda.png

重叠子问题对时间复杂度的影响:

程序验证对比:

#include#include//滴答1000次为一秒,滴答一次1ms,这里的滴答可以联想人的心脏跳动,cpu就是电脑心脏,跳动都是以ms计。#define CLOCKS_PRE_SEC 1000using namespace std;int f(int n){    if(n==1||n==2){        return 1;    }    return f(n-1)+f(n-2);}int main(){  int n=20;//分别使用20 40 50测试  //定义开始时间  time_t startTime=clock();  cout<  time_t endTime=clock();  cout<<"时间:"<<double(endTime-startTime)/CLOCKS_PRE_SEC<<"秒"<}

当n为20时,测试时间为0.001秒:

aa987a15924c56957092e2033b2248f4.png

当n扩大2倍为40时,测试时间为0.451秒:

ccd3507911954c99024cf1c080eccf1e.png

当n扩大2.5倍为50时,测试时间为54.399秒:

cb15ae2196e3a1cb6136ca7e0d68d393.png

结论:通过对比发现,时间的增长根本不是倍数级增长,而是指数级增长!

解决方法:

470eb33412af0d3bf49a54ce03d78077.png

第一种:在自上向下搜索过程中,对重叠子问题提前保存,当再一次遇到直接返回,不需再重新递归,简称记忆化搜索

当n为40时,结果运行时间却接近于0,提升显而易见!

adeaea53c30b507044cb6262bb86d244.png

第二种:动态规划------>自下而上的解决问题

dd10de8211ead6950cbfc16f3e12ca60.png

两种方法对比:

    递归:

            1、递归属于函数的调用,是要占用系统的空间的

            2、递归过程中,出现重叠子问题,函数又出现了重复调用

    动态规划:

            1、循环迭代期间,数组下标对应的空间访问了一次

            2、不需要使用函数额外的开辟和占用空间

动态规划:将原问题拆解成若干子问题,同时保存子问题的答案,使得每个子问题只求解一次,最终获得原问题的答案。

动态规划:爬楼梯问题

有一个楼梯,总共有n阶的台阶。每一次,可以上一个台阶,也可以上两个台阶。问,爬上这样的一个楼梯,一共有多少不同的方法?

当台阶n=3时,可以有这几种爬楼梯方法:

第一种:一次爬一阶---->1 1 1 爬三次

第二种:一次爬一阶,再一次爬两阶---->先爬1,再爬 2

第三种:一次爬两阶,再一次爬一阶---->先爬2,再爬1

递归解决方法:

图解:把大问题依次向前推进一步,假定前面的问题已解决,直到真正遇到已解问题。

d57623c53e3dddb8258dda4980523157.png

记忆化搜索解决重叠子问题:

#includeusing namespace std;int p(int a[],int n){  //只有一个台阶时,只有一种走法   if(n==1){    return 1;   }  //只有两个台阶时,既可以一次一阶,也可以一次两阶   if(n==2){    return 2;   }  //大问题化解为:一次爬一节到达n,也可以一次爬两节到达n   if(a[n]==0){    a[n]=p(a,n-1)+p(a,n-2);  }  return a[n]; }int main(){  int n=3;  int a[n+1]={0};   cout<

endl

; return 0;}

动态规划解决重叠子问题:

#includeusing namespace std;int p(int a[],int n){  //只有一个台阶时,只有一种走法   a[1]=1;  //只有两个台阶时,既可以一次一阶,也可以一次两阶  a[2]=2;   //大问题化解为:一次爬一节到达n,也可以一次爬两节到达n   for(int i=3;i<=n;i++){    a[i]=a[i-1]+a[i-2];  }  return a[n]; }int main(){  int n=3;  int a[n+1]={0};   cout<

endl

; return 0;}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值