出栈方案数思路:
首先,我们设f(n)=序列个数为n的出栈序列种数。(我们假定,最后出栈的元素为k,显然,k取不同值时的情况是相互独立的,也就是求出每种k最后出栈的情况数后可用加法原则,由于k最后出栈,因此,在k入栈之前,比k小的值均出栈,此处情况有f(k-1)种,而之后比k大的值入栈,且都在k之前出栈,因此有f(n-k)种方式,由于比k小和比k大的值入栈出栈情况是相互独立的,此处可用乘法原则,f(n-k)*f(k-1)种,求和便是Catalan递归式。
递推式:
h(0)=h(1)=1
(1)h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n>=2)
(2)h(n)=h(n-1)*(4*n-2)/(n+1);
(3)h(n)=C(2n,n)/(n+1) (n=0,1,2,...)
(4)h(n)=c(2n,n)-c(2n,n-1)(n=0,1,2,...)
应用:
(1)出栈次序
一个栈(无穷大)的进栈序列为1,2,3,…,n,有h(n)种不同的出栈序列
(2)括号化
矩阵连乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n)种)
(3)凸多边形三角划分
在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数h(n)。
(4)给定节点组成二叉搜索树
二叉搜索树:二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
(5)n对括号正确匹配数目
给定n对括号,求括号正确配对的字符串数,n对括号有多少种正确配对的可能呢?答案:h(n)
例题:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1320
Description
zzy今天刚买了两个水瓢A和B,容量都是为1升,童心未泯的他打算用这个水瓢来玩游戏。
首先zzy准备了一个容量可看作无穷大的水缸,刚开始水缸是空的,然后用水瓢A往水缸里加水,用水瓢B把水缸里的水舀出去,当使用 水瓢B把水舀出去时水缸里必须要至少有1升的水。这样子使用N次水瓢A,也使用N次水瓢B,最后水缸会依旧空的。
Input
输入有多个例子,直到文件结束。
每个例子仅含一个数N(0<N<=10000),表示你必须使用N次A水瓢和N次B水瓢。
Output
对于每个例子,请输出一个数,表示一共有多少种正确的舀水方式使得舀水过程中 使用B水瓢时水缸里总会有足够的水。
(由于数字比较大,输出的答案模1000000007)
Sample Input
1
2
Sample Output
1
2
思路:求卡特兰数即可,4个计算公式可选,long long会爆,需要取模,除法不适用于取模,23排除,可选14,第四个公式需要用到组合数学 ,下面选用第一个公式
AC代码
#include<stdio.h>
#include<string.h>
using namespace std;
long long dp[10005];
int main()
{
dp[0] = dp[1] = 1;//递推起始
for (int i = 2; i <= 10000; i++)//递推
{
for (int j = 0; j<i; j++)
{
dp[i] += dp[j] * dp[i - j - 1];
dp[i] %= 1000000007;
}
}
int n;
while (~scanf("%d", &n))
{
printf("%lld\n", dp[n]);
}
}
总结:
<1>取模运算规则不适用于除法!!!一直WA
取模运算:https://blog.csdn.net/y201619819/article/details/81093140
<2>组合数学C(n,m)的求法
https://blog.csdn.net/y201619819/article/details/81094246
<3>卡特兰数的应用