您的位置:首页 > 运维架构

数学 ( 卡特兰数 )——Scoop water ( CSU 1320 )

2016-08-03 16:27 197 查看
题目链接:

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1320

分析:

问题可以转化成求含有n个0和n个1的长度为2n的01串中,从左往右扫时,在每一个位置经过的0不多与1的串01串的个数。

这是一道关于卡特兰(Catalan)数的问题。

题解:

Catalan数的原理

令h(0)=1,h(1)=1,catalan数满足递推式[1] :

h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+..+h(n−1)h(0)(n>=2)

例如:

h(2)=h(0)×h(1)+h(1)×h(0)=1×1+1×1=2

h(3)=h(0)×h(2)+h(1)×h(1)+h(2)×h(0)=1×2+1×1+2×1=5

另类递推式:

h(n)=h(n−1)×(4×n−2)/(n+1);

递推关系的解为:

h(n)=C(2n,n)/(n+1)(n=0,1,2,...)

递推关系的另类解为:

h(n)=C(2n,n)−C(2n,n−1)(n=0,1,2,...)

Catalan数的应用:

括号化

矩阵连乘: P=a1×a2×a3×……×an,依据乘法结合律,不改变其顺序,只用括号表示成对的乘积,试问有几种括号化的方案?(h(n-1)种)

出栈次序

首先,我们设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(n))

凸多边形三角划分

在一个凸多边形中,通过若干条互不相交的对角线,把这个多边形划分成了若干个三角形。任务是键盘上输入凸多边形的边数n,求不同划分的方案数f(n)。比如当n=6时,f(6)=14。

因为凸多边形的任意一条边必定属于某一个三角形,所以我们以某一条边为基准,以这条边的两个顶点为起点P1和终点Pn(P即Point),将该凸多边形的顶点依序标记为P1、P2、……、Pn,再在该凸多边形中找任意一个不属于这两个点的顶点Pk(2<=k<=n-1),来构成一个三角形,用这个三角形把一个凸多边形划分成两个凸多边形,其中一个凸多边形,是由P1,P2,……,Pk构成的凸k边形(顶点数即是边数),另一个凸多边形,是由Pk,Pk+1,……,Pn构成的凸n-k+1边形。

此时,我们若把Pk视为确定一点,那么根据乘法原理,f(n)的问题就等价于——凸k多边形的划分方案数乘以凸n-k+1多边形的划分方案数,即选择Pk这个顶点的f(n)=f(k)×f(n-k+1)。而k可以选2到n-1,所以再根据加法原理,将k取不同值的划分方案相加,得到的总方案数为:f(n)=f(2)f(n-2+1)+f(3)f(n-3+1)+……+f(n-1)f(2)。看到此处,再看看卡特兰数的递推式,答案不言而喻,即为f(n)=h(n-2) (n=2,3,4,……)。

给定节点组成二叉搜索树

给定N个节点,能构成多少种不同的二叉搜索树?

(能构成h(N)个)

(这个公式的下标是从h(0)=1开始的)

对于在n位的2进制中,有m个0,其余为1的catalan数为:C(n,m)-C(n,m-1)。

Catalan数计算代码:

//递归求法,耗空间都是从0开始
unsigned long long catalannumber1(int n)
{
if(n == 0)
return 1;
else
return (4 * n - 2) * catalannumber1(n-1) / (n + 1);
}
//递推求法,耗时间
unsigned long long catalannumber2(int n)
{
unsigned long long cn = 1;
int i;

for(i=1; i<=n; i++)
cn = (4 * i - 2) * cn / (i + 1);

return cn;
}
//递推法求,(存储之前的数据),省时间
long long f[10005];
int n;
const int mod=1000000007;
int main()
{
f[0]=1;
for(int i=1;i<=10000;i++)
for(int j=0;j<i;j++)
f[i]=((f[j]*f[i-1-j])%mod+f[i])%mod;

while(scanf("%d",&n)!=EOF)
{
printf("%lld\n",f
);
}
return 0;
}


一组卡特兰数

0: 1,

1: 1,

2: 2,

3: 5,

4:14,

5:42,

6:132,

7:429,

8:1430,

9:4862,

10:16796,

11:58786,

12:208012,

13:742900,

14:2674440,

15:9694845,

16:35357670,

17:129644790,

18:477638700,

19:1767263190,

20:6564120420,

21:24466267020,

22:91482563640,

23:343059613650,

24:1289904147324,

25:4861946401452,

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息