这篇博客主要讲的是动态规划入门,即动态规划的思想,而且再讲解动态规划的最简单的一个方法。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; }