爬楼梯问题

有一楼梯共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\n",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\n",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\n",f[20]);
	
	  return 0;

}

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

小结一下

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

posted @ 2015-05-11 12:26  樱风凛  阅读(475)  评论(0编辑  收藏  举报