基本算法--递推

来源:互联网 发布:拒绝退款 淘宝介入 编辑:程序博客网 时间:2024/06/16 03:32

汉诺塔问题

将n个盘子从a移动到c所需要的最少移动次数?
首先设f[n]为移动n个盘子所需次数,将该问题分为三步:
(1)先将前n-1个盘子从a移动到b
(2)将最大的盘子移动到c
(3)最后将n-1个盘子从b移动到c
递推式为:f[n]=2*f[n-1]+1

放球问题

N球放入M盒,不允许出现空盒,共有多少种方案?
f[i][j]为将i个球放入j个盒子的方案数
  有i个球,首先在j个盒子中放入一个球,方案数为j*f[i-1][j]
  然后将i-1个球放入j-1个盒子中,方案数为f[i-1][j-1]
递推式为:f[i][j]=j*f[i-1][j]+f[i-1][j-1]

#include <iostream>#include<cstring>using namespace std;#define ll long longll res[25][25];int main(){    memset(res,0,sizeof(res));    int m,n,i,j;    cin>>m>>n;    for(i=1;i<=m;++i)    {        res[i][i]=1;        res[i][1]=1;    }    for(i=2;i<=m;++i)        for(j=2;j<=n;++j)            res[i][j]=j*res[i-1][j]+res[i-1][j-1];    cout<<res[m][n]<<endl;    return 0;}

使用一维数组节省内存空间

#include <iostream>#include<cstring>using namespace std;#define ll long longll f[21];int main(){    memset(f,0,sizeof(f));    int m,n,i,count=0;    cin>>m>>n;    for(i=1;i<=m;i++)    {        f[1]=f[i]=1;        for(count=i-1;count>1;count--)            f[count]=count*f[count]+f[count-1];    }    cout<<f[n]<<endl;    return 0;}

错排问题(装错信箱问题)

用A、B、C……表示写着n位友人名字的信封,a、b、c……表示n份相应的写好的信纸。把错装的总数为记作D(n)。假设把a错装进B里了,包含着这个错误的一切错装法分两类:  (1)b装入A里,这时每种错装的其余部分都与A、B、a、b无关,应有D(n-2)种错装法。     (2)b装入A、B之外的一个信封,这时的装信工作实际是把(除a之外>  的)n-1份信纸b、c……装入(除B以外的)n-1个信封A、C……,显然这时装错的方法有D(n-1)种。总之在a装入B的错误之下,共有错装法D(n-2)+D(n-1)种。a装入C,装入D……的n-2种错误之下,同样都有D(n-1)+D(n-2)种错装法因此D(n)=(n-1)[D(n-1)+D(n-2)]

递推之卡特兰数

四类卡特兰数的应用:
1.括号化问题。  矩阵链乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种)
2.出栈次序问题。  一个栈(无穷大)的进栈序列为1,2,3,..n,有多少个不同的出栈序列?
3.将多边行划分为三角形问题。  将一个凸多边形区域分成三角形区域的方法数?
类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?
给顶节点组成二叉树的问题。
给定N个节点,能构成多少种形状不同的二叉树?  (一定是二叉树!)先去一个点作为顶点,然后左边依次可以取0至N-1个相对应的,右边是N-1到0个,两两配对相乘,就是h(0)*h(n-1) + h(2)*h(n-2) + … + h(n-1)h(0)=h(n)

利用卡特兰数递推求解:

令h(0)=1,h(1)=1,catalan数满足递推式:
h(n)= h(0)*h(n-1)+h(1)*h(n-2) + … + h(n-1)*h(0) (n>=2)
另类递推式: h(n)=((4*n-2)*h(n-1)/(n+1));
递推关系的解为:
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
递推关系的另类解为:
h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,…)

#include <iostream>#include<cstring>using namespace std;#define ll long longll res[35];ll caculate(int n){    if(res[n])  return res[n];    return  res[n]=(4*n-2)*caculate(n-1)/(n+1);}int main(){    memset(res,0,sizeof(res));    res[0]=1;    res[1]=1;    int n;    cin>>n;    cout<<caculate(n)<<endl;    return 0;}
原创粉丝点击