积跬步至千里——算法强化训练(8)卡特兰数相关题目求解

在编程之美上又看到卡特兰数的题目,所以就把这类题目做个总结。

至此,已经遇到过得卡特兰数的题目有:

1、12个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?

解答:12个高矮不同,则可以编号1 2 3 4 5 6 7 8 9 10 11 12 ,现在0代表第一排,1代表第二排 

000000111111是一个合法序列,010101010101也是一个合法序列,可以看到对于每个1,只要前面的0的个数大于等于1的个数就是一个合法序列,011000001111,由于第2个1,前面0只有1个,1有两个,不符合。

换个角度,1号1的位置大于1号0的位置,2号1的位置大于2号0的位置。。。。,6号1的位置大于6号0的位置


2、用S表示入栈,X表示出栈,那么合法的序列有多少个(S的个数为n)

解答:出栈X前必须要有大于等于X个数的S操作,SSSSXXXX合法,SXSXSXSX合法,但是SXXSSXSX就不合法,和上题一样,1号X的位置要大于1号S的位置,2号X的位置要大于2号S的位置,以此类推


3、括号化问题。矩阵链乘: P=A1×A2×A3×……×An,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?

解答:每个右括号前面要有大于等于左括号的个数,和前面题目一样,1号右括号位置大于1号左括号,2号右括号位置大于2号左括号。。。


4假设有2N个人在排队买票,其中有N个人手持50元的钞票,另外有N个人手持100元的钞票,假设开始售票时,售票处没有零钱,问这2N个人有多少种排队方式,不至使售票处出现找不开钱的局面?

解答:每个持100的前面必须要有大于等于持50的人的个数,即1号100必须在1号50右边,2号100必须在2号50右边。。。直到n号


5、将多边行划分为三角形问题。将一个凸多边形区域分成三角形区域(划分线不交叉)的方法数?

类似:在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?

6、给顶节点组成二叉树的问题。
  给定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(N)个)


卡特兰数

原理:
令h(1)=1,catalan数满足递归式:
h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) (其中n>=2)
另类递归式:
h(n)=((4*n-6)/(n))*h(n-1);
该递推关系的解为:
h(n)=C(2n,n)/(n + 1) (n=1,2,3,...)


talk is cheap,show the code:

#include <iostream>
using namespace std;

int bit_cnt(int n)//计算非负整数中二进制数中1的个数
{
	int result = 0;
	for (; n; n &= n-1, ++result);
	return result;
}

int main(void)
{
	int F[6], B[6];//F代表前排 B代表后排
	int i,j,k,state,ok,ans = 0;
	for (state = 0; state < (1 << 12); ++state)
	{
		if (bit_cnt(state) == 6)
		{
			i = j = 0;
			for (int k = 0; k < 12; ++k)//确定每个0和1所在的位置
			{
				if(state&(1<<k))
					F[i++] = k;
				else
					B[j++] = k;
			}
			ok = 1;
			for (k = 0; k < 6; ++k)//筛选满足条件的排列
			{
				if (B[k] < F[k])
				{
					ok = 0;
					break;
				}
			}
			ans += ok;
		}
	}
	cout << ans << endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值