Dynamic Programming 求解Catalan数中第n项的值

        Catalan是一个组合数列,即一组情景下排列的组合数,前k次操作,后k个操作,前k次操作必须在后k次操作之前完成,注2k次操作可相互交叉。

       递推式:f(n+1)=∑f(i)*f(n-i)     ,i∈[0,n]     

        即:f(n)=∑f(i)*f(n-1-i)         ,i∈[0,n-1]

       f(0)=1;

       n =  0,  1,  2,  3,  4,  5,  6,   7,   8,    9  

       f(n)=1,  1,  2,  5,  14,  42, 132, 429, 1430, 4862, …

       仅根据递推式来计算第n项的Catalan数较简单,只要一个递归操作即可,但是可发现递推式中包含重复计算项,因此根据DP思想,可通过memorize方法存储已经计算得到的项,即利用一个向量vector<int>memorize存储n个项的值,那么如何判断一个值是否已被计算呢?最简单的方法就是初始化memorize的值与所有正确答案的值都不相同,即当正确答案都为正数时,初始化memorize的值为负数,同时在递归中通过别名进行传递。

      注意,在编程的时传进来的n是递推式中的n+1项,所以子递归时为n-1-i,一定要注意,在子递归时,传进去的数要越来越小,不然会形成死循环递归,因为递归在原地踏步,而没有收敛。不收敛的递归无法递归到终止项,但也可根据实际需求功能强行设定终止条件。

      本文的具体算法实现如下:

int DynamicProgramming::catalanNumber(int n)
{
	//------------通过DP算法保存中间重复结果----------------
    std::vector<int> f;                  //fi为中间值
    f.resize(n+1);
    for (int i = 0; i <= n;i++)
    {
		f[i] = -1;
    }

    int fn = conquerCatalan(f, n);

    return fn;

}


int DynamicProgramming::conquerCatalan(std::vector<int> &f, int n)
{
	if (f[n]!=-1)
	{
		return f[n];
	}

	int result = 0;
	if (n == 0)
	{
		result = 1;
	}
	else
	{
		for (int i = 0; i <= n - 1; i++)
		{
			result += conquerCatalan(f, i)*conquerCatalan(f, n - 1 - i);                  //fn==f(i)或者f(n-i)
		}   
	}

	f[n] = result;
	return result;
}

        总结:如果单就Catalan数列本身仅仅是一串数列,但这个数的第n项是一些实际应用问题中出现的排列组合,比如n个不同数进栈出栈的全排列问题等等,该类问题的一个共性特点是总共有2n次操作,2k∈2n次操作,前k次操作必须不小于后k次操作,前后k次操作可相互交叉。像这类问题就可直接根据Catalan递推式求解,那为什么这类问题可用Catalan递推式计算呢?应该是这类实际的问题在数学上归纳成了Catalan数列?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值