算法之动态规划(递推求解一)

这篇博客主要讲的是动态规划入门,即动态规划的思想,而且再讲解动态规划的最简单的一个方法。spa

首先,什么是动态规划?code

  动态规划是经过拆分问题,定义问题状态和状态之间的关系,使得问题可以以递推(或者说分治)的方式去解决。其实就是分解问题,分而治之。可能这样说你们都不太理解,其实这个有点相似于数学中的递推公式。来举一个简单的例子,看下边这个题:blog

  N阶楼梯上楼问题:一次能够走两阶或一阶,问有多少种上楼方式。递归

  这就是动态规划就简单的一个列子。拿到这个题,你们是否是都有点迷,这个到底怎么作?是否是没有思路,那么按照动态规划思想,咱们能够先分析下问题,每次都有两种跳法,分别是一阶或者两阶,那么若是当前是第n个台阶,那么跳法是否是是(n-1)台阶的跳法数加上(n-2)台阶的跳法数?若是划算成公式是F(n) =  F(n-1)+F(n-2)。F(n)表明第n阶台阶的跳法的数量。博客

  这不就至关于找到了一个递推公式,而后来进行计算。具体的代码实现以下(采用的是非递归):数学

#include <stdio.h>    
     
int main()    
{    
        int i,N;    
        long long a[90];    
        while(~scanf("%d",&N))    
        {                 
                a[1]=1;    
                a[2]=2;    
                for(i=3;i<=N;i++)    
                        a[i]=a[i-1]+a[i-2];    
                printf("%lld\n",a[N]);    
        }    
             
        return 0;    
             
}   

 

下边再举一个列子来辅助理解:io

  n封信放入n个信封,要求所有放错,共有多少种放法,记n个元素的错排总数为f(n)入门

  对于这个题,咱们能够采用和上述同样的思路,咱们是否要考虑下找一个相似的递推公式等来解决。思路以下:class

  在任意一种错装方案中,假设n号信封里装的是k号信封的信,而n号信封里的信则装在m号信封里。咱们按照k和m的等值与否将总的错装方式分为两类。  若k不等于m,交换n号信封和m号信封的信后,n号信封里装的刚好是对应的信,而m号信封中错装k号信封里的信,即除n号信封外其他n-1个信封 所有错装,其错装方式等于 F[n - 1],又因为m的n-1个可能取值,这类错装方式总数为(n - 1)* F[n - 1]。也能够理解为,在 n-1个信封错装的 F[n - 1]种方式的基础上,将n号信封所装的信与n - 1个信封中任意一个信封(共有 n-1 中选 择)所装的信作交换后,获得全部信封所有错装的方式数。另外一种状况,若 k 等于 m,交换 n 号信封和 m 号信封的信后,n 号信封和 m 号信封里装的刚好是对应的信,这样除它们以外剩余的 n-2 个信封所有错装,其 错装方式为 F[n - 2],又因为 m 的 n-1 个取值,这类错装方式总数为(n - 1)* F[n - 2]。也能够理解为,在 n - 2 个信封所有错装的基础上,交换最后两个信封中的 信(n 号信封和 1 到 n-1 号信封中任意一个,共有 n-1 种选择),使全部的信封所有 错装的方式数。  综上所述,F[n] = (n - 1) * F[n - 1] + (n - 1) * F[n - 2]。这就是错排公式。基础

  具体代码以下:

#include <stdio.h>
Long long F[21]; //数值较大选用long long
int main () {
  F[1] = 0;
  F[2] = 1; //初始值
  for (int i = 3;i <= 20;i ++)
    F[i] = (i - 1) * F[i - 1] + (i - 1) * F[i - 2]; //递推求得数列每个数字
  int n;
  while (scanf ("%d",&n) != EOF) {
    printf("%lld\n",F[n]); //输出
  }
  return 0;
}
相关文章
相关标签/搜索