按身高排成两队问题 catalan数

题目源自于阿里巴巴校招笔试题。
题目:12个高矮不同的人,排成2排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多
少种?

思路:假设12个人的身高为,0 1 2 3 4 5 6 7 8 9 10 11。
我们先把这12个人从低到高排列,然后,选择6个人排在第一排,那么剩下的6个肯定是在第二排。
用0表示对应的人在第一排,用1表示对应的人在第二排。

那么含有6个0,6个1的序列,就对应一种方案。
比如000000111111就对应着
第一排:0 1 2 3 4 5
第二排:6 7 8 9 10 11
010101010101就对应着
第一排:0 2 4 6 8 10
第二排:1 3 5 7 9 11
问题转换为,可以怎么样安排这些0/1?


我们来观察,什么样的序列符合要求。
对于某一个1的出现,观察在这个1之前的这些数(比当前的1所对应的人个子小的人),所对应的这些人:要么是在当前
这个1的人同一排左边(即为1),要么是在第一排(即为0)。

而且,肯定要有一个0的(在当前这个1的人的前正方)。

那么,对于当前这个1之前的数,我们的要求就是:0的个数大于1的个数


由此看出这是一个由小到大的递推问题,另外很明显这是个排列组合问题,考虑使用递归来寻找可能的状态空间。对于序列从小开始逐步扩大子空间,当序列到达所求长度时递归结束。


代码:

#include <stdio.h>
int num = 0;
const int N = 12;
int list[N];

void printArray(int data[])
{
	int i;
	for(i=0;i<N;i++)
		printf("%d  ",data[i]);
	printf("\n");
}

void ProduceArray(int data[], int index, int n_0)
{
	if(index < N) //组合序列长度没到达
	{
		//0的个数不能超过总数的一般
		if(n_0 < N/2) 
		{
			data[index] = 0;
			ProduceArray(data, index+1, n_0 + 1);
		}
		//0的个数不能超过总数的一般
		//并且0的个数要大于1的个数
		if((index  - n_0 < N/2)&&(index  - n_0 < n_0)) 
		{
			data[index] = 1;
			ProduceArray(data, index+1, n_0);
		}
	}
	else
	{
		printArray(data);
		num++;
	}
}

void fun()
{
	int i;
	list[0] = 0;
	ProduceArray(list, 1, 1);
}
int main()
{
	fun();
	printf("%d\n",num);
	return 1;
}


问题等价:

    换个角度去思考这个问题。这里要求这个序列从左到右,或者说序列的长度从小到大,都需要满足0的个数大于1的个数。那么可以联想到栈,把0看成入栈操作,把1看成出栈操作,如果1的个数多余0的个数则会出错。现在就是在合理的安排6个0和6个1,使得能够完成出入栈。于是问题就等价为求6个元素构成合法的入栈出栈序列有多少个?
    这就是catalan数,这里只是用于栈,等价地描述还有,二叉树的枚举,多边形分成三角形的个数,圆括弧插入公式中的
方法数,其通项是c(2n, n)/(n+1)

你可能感兴趣的:(按身高排成两队问题 catalan数)