1. 问题描述:
5个人有5元,另外5个人有10元,问有多少种10个人的排列方法使得是要有10元的人买票就能有5元找零。
2. 结论公式:
总数 = C(n, 2n) - C(n + 1, 2n)
3. 问题由来:
编号为1到n的n个元素,顺序的进入一个栈,则可能的出栈序列有多少种?
4. 另一个模型:
一个n×n的正方形网格,从左上角顶点到右下角顶点,只能向右走和向下走,且只能在此正方形网络的下三角范围内,问共有多少种走法。如果将向右走对应上述问题的进栈,向下走对应上述问题的出栈。
5. 等价问题:
n个1和n个0组成一个2n位的2进制数,要求从左到右扫描,1的累计数不小于0的累计数,试求满足这条件的数有多少?
6. 基本思路:
从C(n, 2n)中减去不符合要求的方案数即为所求。不合要求的数指的是从左而右扫描,出现0的累计数超过1的累计数的数。
7. 不合要求的特征:
不合要求的数的特征是从左而右扫描时,必然存在某一奇数2m+1位,其中共出现m+1个0的累计数,和m个1的累计数。此后的2(n-m)-1位上有n-m个1,n-m-1个0。如若把后面这部分2(n-m)-1位中的0与1相互替换,使之成为n-m个0,n-m-1个1,结果得1个由n+1个0和n-1个1组成的2n位数。因此,得出结论:一个不合要求的数对应于一个由n-1个0和n+1个1组成的一个排列。
8. 一一对应关系:
反过来,任何一个由n+1个0,n-1个1组成的2n位数,由于0的个数多2个,2n是偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面的部分,令0和1互换,使之成为由n个0和n个1组成的2n位数。即n+1个0和n-1个1组成的2n位数,必对应于一个不合要求的数。因此,得出结论:由n+1个0和n-1个1组成的2n位数,与由n个0和n个1组成的2n位数中从左向右扫描出现0的累计数超过1的累计数的数一一对应。
9. 举例:
例如:10100101
是由4个0和4个1组成的8位2进制数。但从左而右扫描在第5位出现0的累计数3超过1的累计数2,它对应于由3个1,5个0组成的10100010。反之:10100010对应于10100101。因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应,因此,得出公式:
C(n, 2n) - C(n+1, 2n)
10. 另一种思维:
可以把这个问题描述为一个二元组,(n, 0)表示有n个元素等待进栈,0个元素已进栈,这相当于问题最初的状况。接着问题转化为(n-1, 1)。可以这么说(n, 0)=(n-1, 1)。
而对于(n-1, 1)则相当于(n-1,0)+(n-2,2)。(n-1, 0)表示栈中的一个元素出栈,(n-2, 2)表示又有一个元素入栈。
把问题一般话,则(n, m)的排列问题可以转化为(n, m-1) + (n-1, m+1)此时m>=1,因为必须栈中有元素才可以出栈。当m=0则(n, 0)的问题只能转化为(n-1, 1)。当问题为(0, m)时得到递归边界,这个问题的解是只有一种排列。
5个人有5元,另外5个人有10元,问有多少种10个人的排列方法使得是要有10元的人买票就能有5元找零。
2. 结论公式:
总数 = C(n, 2n) - C(n + 1, 2n)
3. 问题由来:
编号为1到n的n个元素,顺序的进入一个栈,则可能的出栈序列有多少种?
4. 另一个模型:
一个n×n的正方形网格,从左上角顶点到右下角顶点,只能向右走和向下走,且只能在此正方形网络的下三角范围内,问共有多少种走法。如果将向右走对应上述问题的进栈,向下走对应上述问题的出栈。
5. 等价问题:
n个1和n个0组成一个2n位的2进制数,要求从左到右扫描,1的累计数不小于0的累计数,试求满足这条件的数有多少?
6. 基本思路:
从C(n, 2n)中减去不符合要求的方案数即为所求。不合要求的数指的是从左而右扫描,出现0的累计数超过1的累计数的数。
7. 不合要求的特征:
不合要求的数的特征是从左而右扫描时,必然存在某一奇数2m+1位,其中共出现m+1个0的累计数,和m个1的累计数。此后的2(n-m)-1位上有n-m个1,n-m-1个0。如若把后面这部分2(n-m)-1位中的0与1相互替换,使之成为n-m个0,n-m-1个1,结果得1个由n+1个0和n-1个1组成的2n位数。因此,得出结论:一个不合要求的数对应于一个由n-1个0和n+1个1组成的一个排列。
8. 一一对应关系:
反过来,任何一个由n+1个0,n-1个1组成的2n位数,由于0的个数多2个,2n是偶数,故必在某一个奇数位上出现0的累计数超过1的累计数。同样在后面的部分,令0和1互换,使之成为由n个0和n个1组成的2n位数。即n+1个0和n-1个1组成的2n位数,必对应于一个不合要求的数。因此,得出结论:由n+1个0和n-1个1组成的2n位数,与由n个0和n个1组成的2n位数中从左向右扫描出现0的累计数超过1的累计数的数一一对应。
9. 举例:
例如:10100101
是由4个0和4个1组成的8位2进制数。但从左而右扫描在第5位出现0的累计数3超过1的累计数2,它对应于由3个1,5个0组成的10100010。反之:10100010对应于10100101。因而不合要求的2n位数与n+1个0,n-1个1组成的排列一一对应,因此,得出公式:
C(n, 2n) - C(n+1, 2n)
10. 另一种思维:
可以把这个问题描述为一个二元组,(n, 0)表示有n个元素等待进栈,0个元素已进栈,这相当于问题最初的状况。接着问题转化为(n-1, 1)。可以这么说(n, 0)=(n-1, 1)。
而对于(n-1, 1)则相当于(n-1,0)+(n-2,2)。(n-1, 0)表示栈中的一个元素出栈,(n-2, 2)表示又有一个元素入栈。
把问题一般话,则(n, m)的排列问题可以转化为(n, m-1) + (n-1, m+1)此时m>=1,因为必须栈中有元素才可以出栈。当m=0则(n, 0)的问题只能转化为(n-1, 1)。当问题为(0, m)时得到递归边界,这个问题的解是只有一种排列。
11. 求解例程:
int Catalan(int n, int m)
{
/* 参数合法性检查 */
if (n < 0 || m < 0)
{
return 0;
}
/* 递归边界 */
if (0 == n)
{
return 1;
}
/* 对应于(n, 0)情形 */
if (0 == m)
{
return Catalan(n - 1, 1);
}
else // 对应于(n, m)情形
{
return Catalan(n, m - 1) + Catalan(n - 1, m + 1);
}
}