天天看點

Catalan 卡特蘭數

卡特蘭數又稱卡塔蘭數,英文名Catalan number,是組合數學中一個常出現在各種計數問題中出現的數列。以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)的名字來命名,其前幾項為 : 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …

Catalan的遞推關系

令 h ( 0 ) = 1 , h ( 1 ) = 1 h(0)=1,h(1)=1 h(0)=1,h(1)=1,catalan數滿足遞推式

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

cat[0]=cat[1]=1;
for(int i=2;i<=n;++i)
for(int j=0;j<i;++j)
cat[i]+=cat[j]*cat[i-j-1];
           

遞推複雜度為 O ( n 2 ) O(n^2) O(n2)

令 h ( 0 ) = 1 , h ( 1 ) = 1 h(0)=1,h(1)=1 h(0)=1,h(1)=1

則有 h ( n ) = h ( n − 1 ) ∗ ( 4 ∗ n − 2 ) / ( n + 1 ) h(n)=h(n-1)*(4*n-2)/(n+1) h(n)=h(n−1)∗(4∗n−2)/(n+1)

cat[0]=cat[1]=1;
for(int i=2;i<=n;++i)
cat[i]=cat[i-1]*(4*i-2)/(i+1);
           

遞推複雜度為 O ( n ) O(n) O(n)

h ( n ) = C 2 n n / ( n + 1 ) h(n)=C_{2n}^n/(n+1) h(n)=C2nn​/(n+1)

h ( n ) = C 2 n n − C 2 n n − 1 h(n)=C_{2n}^n-C_{2n}^{n-1} h(n)=C2nn​−C2nn−1​

代碼就不填了= =

Catalan的應用

入棧出棧

Q:給定n個數,進棧的序列是1,2,3,4,……n,有多少個不同的出棧次序

A:

h(n)表示個數為n的序列的出棧次序種數

假設最後出棧的元素是k

在k入棧前k前面的元素都出棧,是以有 h ( k − 1 ) h(k-1) h(k−1)種

k後面的元素在k之前出棧,是以有 h ( n − k ) h(n-k) h(n−k)種

運用乘法原理有 h ( n ) = h ( k − 1 ) ∗ h ( n − k ) h(n)=h(k-1)*h(n-k) h(n)=h(k−1)∗h(n−k)

由于k可以取1到n,根據加法原理得

h ( n ) = h ( 0 ) ∗ h ( n − 1 ) + h ( 1 ) ∗ h ( n − 2 ) + . . . + h ( n − 1 ) ∗ h ( 0 ) ( n &gt; = 2 ) h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n&gt;=2) h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)∗h(0)(n>=2)

也就是卡特蘭數得遞推式

平衡括号

Q:有n個左括号,n個右括号,總共2*n個括号,有多少種合法比對方式,

A:

将左括号視為入棧,右括号視為出棧

那麼這個問題就轉化成了将n個左括号入棧,有多少種合法出棧次序得問題

也就是上面的出棧入棧問題,答案就是 h ( n ) h(n) h(n)

二叉樹的形态

Q:有n個結點得二叉樹,可以有多少種不同形态

A:

以h(n)表示有n個節點的二叉樹可以有得不同形态數

假設其根得左子樹有k個節點

那麼其左子樹有 h ( k ) h(k) h(k)個不同形态,右子樹有 h ( n − k − 1 ) h(n-k-1) h(n−k−1)個不同形态

根據乘法原理 h ( n ) = h ( k ) ∗ h ( n − k − 1 ) h(n)=h(k)*h(n-k-1) h(n)=h(k)∗h(n−k−1)

k可以取0-n

則有 h ( n ) = h ( 0 ) ∗ h ( n − 1 ) + h ( 1 ) ∗ h ( n − 2 ) + . . . + h ( n − 1 ) ∗ h ( 0 ) ( n &gt; = 2 ) h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)*h(0) (n&gt;=2) h(n)=h(0)∗h(n−1)+h(1)∗h(n−2)+...+h(n−1)∗h(0)(n>=2)

滿足卡特蘭數遞推式

走方格

Q:一個 n*n 的方格,從左下角走到右上角,隻能向右和向上走,但是不能繞過左下角和右上角确定的對角線,問有多少種走法?

A:

要走到右上角,需要向右走n布,向上走n步

向右走看作進棧,向左走看作出棧,本質就是n個數出棧次序的問題

還有很多應用

待更。。。。

Catalan數例題

題目背景

盛況空前的足球賽即将舉行。球賽門票售票處排起了球迷購票長龍。

按售票處規定,每位購票者限購一張門票,且每張票售價為50元。在排成長龍的球迷中有N個人手持面值50元的錢币,另有N個人手持面值100元的錢币。假設售票處在開始售票時沒有零錢。試問這2N個球迷有多少種排隊方式可使售票處不緻出現找不出錢的尴尬局面。

題目描述

例如當n=2是,用A表示手持50元面值的球迷,用B表示手持100元錢的球迷。則最多可以得到以下兩組不同的排隊方式,使售票員不至于找不出錢。

第一種:A A B B

第二種:A B A B

對于給定的n (0≤n≤20),計算2N個球迷有多少種排隊方式,可以使售票處不至于找不出錢。

輸入格式:

一個整數,代表N的值

輸出格式:

一個整數,表示方案數

分析

一個A買票後售票處就積累50元錢

一個B買票需要售票處找零50元錢

說明在一個B買票前至少需要一個A買過票

那麼我們就可以将A看作左括号,B看作右括号

問題就是要求合法得括号比對,即Catalan數

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;

int n;
ll cat[50];

int main()
{
    scanf("%d",&n);
    cat[0]=cat[1]=1;
    
    for(int i=2;i<=n;++i)
    cat[i]=cat[i-1]*(4*i-2)/(i+1);
    
    cout<<cat[n];
    return 0;
}