zoukankan      html  css  js  c++  java
  • 爬楼梯问题

    有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?

    一个可以运行的程序,解释在后边:

    #include "stdio.h"
    
    int f(int x){
    
    
    	if(x==1)
    
        return 1;
    
        if(x==2)
    
        return 2;
    
        return (f(x-1)+f(x-2));
    
    }
    
    	int main(){
    	
    	int n;
    	
    	scanf("%d",&n);
    	
    	printf("%d",f(n));
    	
    	return 0;
    
    }
    

    方法一,直接思考问题:

    设f(x)=【剩x阶时,迈楼梯的方法总数】。首先迈出第一步,如果一次迈一阶,剩下x-1阶,方法总数为f(x-1);如果一次迈两阶,剩下x-2阶,方法总数为f(x-2);这里f(x-1) f(x-2)都是我们不知道的。这里只是找出一个递推关系式。即f(x)=f(x-1)+f(x-2)。容易发现,f(1)=1,f(2)=2。

    方法二,抽象成数学问题,找出递推关系式:

    如果x为1时,只可以迈一步,共有一种方法。

    如果x为2时,可以一次迈一步,也可以一次迈两步,共有两种方法。

    如果x为3时,可以先1,后2;可以先2,后1;也可以1,1,1;共有三种方法。满足f(1)+f(2)。

    如果x为4时,1,1,1,1; 1,2,1; 1,1,2; 2,1,1; 2,2; 共有五种方法。满足f(2)+f(3)。

    ......

    发现规律:f(x)=f(x-2)+f(x-1);

    总结:

    做递归函数时,我们不妨先从较小的数开始做实验,找出潜在的数学规律,抽象成数学问题。【即找出递推关系式】。这样比直接思考问题要简单一些。

    一个楼梯有20级,每次走1级或两级,请问从底走到顶一共有多少种走法?

    分析:假设从底走到第n级的走法有f(n)种,走到第n级有两个方法,一个是从(n-1)级走一步,另一个是从第(n-2)级走两步,前者有f(n-1)种方法,后者有f(n-2)种方法,所以有f(n)=f(n-1)+f(n-2),还有f(0)=1,f(1)=1.

    递归编程实现

    程序1

    #include <stdio.h>
    
    int f(int n)
    
    {
    
        if(n==0 || n==1) return 1;
    
        else return f(n-1)+f(n-2);
    
    }
    
    int main()
    
    {
    
         printf("%d
    ",f(20));
    
         return 0;
    
    }
    

    现在来说说动态规划的基本思想

    动态规划的关键是发现子问题和怎么记录子问题,以上面的例子说明

    (1)对子问题可递归的求解,当n>1时,f(n)=f(n-1)+f(n-2);否则,f(1)=f(0)=1;

    (2)这些子问题是有重叠的,即求解某个问题时,某些子问题可能需要求解多次。例如求解f(5)时,f(2)就被求解了3次。

    在上面两个条件下,用动态规划的方式来求解会高效很多。就是把子问题记录下来,每个子问题只求解一次,从而提高了效率。

    程序2

    #include <stdio.h>
    
    int result[100];
    
    int f(int n)
    
    {
    
      int res;
    
      if(result[n]>=0) return result[n];
    
      if(n==0 || n==1) res=1;
    
      else res=f(n-1)+f(n-2);
    
      result[n]=res;
    
      return res;
    
    }
    
    int main()
    
    {
    
      int i;
    
      for(i=0;i<=20;i++)
    
        result[i]=-1;
    
      printf("%d
    ",f(20));
    
      return 0;
    
    }
    

    程序3

    #include <stdio.h>
    
    int f[100];
    
    int main()
    
    {
    	
    	  int i;
    	
    	  f[0]=1;
    	
    	  f[1]=1;
    	
    	  for(i=2;i<=20;i++)
    	
    	   f[i]=f[i-1]+f[i-2];
    	
    	  printf("%d
    ",f[20]);
    	
    	  return 0;
    
    }
    

    程序3是否让你想起了那个兔子繁殖的问题呢?

    小结一下

    动态规划,采用分治的策略,把求最优解问题分解为求若干子问题的最优解,记录子问题的解,化繁为简,很实用,也很高效。

  • 相关阅读:
    [原译]关于源代码控制的五个误区
    [原译]AVALONDOCK 2.0入门指南第一部分
    [原译]11个高效的VS调试技巧
    【原译】一个可定制的WPF任务对话框
    [原译]YAXLib XML序列化神器
    为什么SIZEOF(STR.SUBSTR(0,3).C_STR())=8?
    C#实现GIF图片反转
    转 基于jquery ajax 用户无刷新登录详解介绍
    php中判断文件空目录是否有读写权限
    防止mysql用户root密码弱口令的攻击方法
  • 原文地址:https://www.cnblogs.com/fazero/p/4494203.html
Copyright © 2011-2022 走看看