Catalan數


Catalan 數

引入

Problem:

具有n個節點的二叉樹的形態有多少種?

分析:

因為二叉樹定義具有遞歸性,左子樹有i個節點,那么右子樹有n-i-1個節點,根據計數原理:

\[f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ),f\left ( 0 \right )=1,f\left ( 1 \right )=1 \]


Catalan數

這里的:

\[f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ) \]

就叫做卡特蘭數,該數列的前若干項是:

1,2,5,14,42,132,429,1430....

所以增長速度是非常快的。

常見的Catalan數表達式

1、遞推式:

\[f\left ( n \right )=\sum_{i=0}^{n-1}f\left ( i \right )\cdot f\left ( n-i-1 \right ),f\left ( 0 \right )=1 \]

2、另類遞推式:

\[f\left ( n \right )=\frac{(4n-2)f\left ( n-1 \right )}{n+1} \]

3、通向式(重要,常用):

\[f\left ( n \right )=\frac{C\begin{matrix} n\\ 2n \end{matrix}}{n+1} \]

4、通向式2:

\[f\left ( n \right )=C\begin{matrix} n\\ 2n \end{matrix} -C \begin{matrix} n-1\\ 2n \end{matrix} \]

利用通向式求Catalan(n) Code

#define ll long long
ll Catalan(ll n){
	ll ans=1;
	for(ll i=n+1;i<=2*n;i++){
		 ans=ans*i/(i-n);
		 printf("%d %d %lld\n",i,i-n,ans);
	}
	return ans/(n+1);
}

應用:

•Cn表示n個節點不同形態的二叉樹個數。

•Cn表示n的入棧序列對應的合法出棧序列的個數。(luogu P1044)

​ 變式:

​ •n個0和n個1,構造一個長度為2n的序列,使得序列的任意前綴中1的個數不 少於0的個數,這樣的序列有多少種?

​ •n個矩陣相乘,用括號改邊運算順序,有多少種?(ps:n個矩陣相乘需要n-1對括號,再增加是無意義的)

​ •游樂園門票1元一張,每人限購一張。現在有10個小朋友排隊購票,其中5個小朋友每人只有1元的鈔票一張,另5個小朋友每人只有2元的鈔票一張,售票員沒有准備零錢。問:有多少種排隊方法,使售票可以正常進行下去?

•凸多邊形分割成三角形方案數

圖像法

n·n的矩陣,每次只能往右或往上走1個單位,問從(0,0)走到n·n,且路線一直處於y=x之下的方法總數是多少?

只需要n步的向右和n步的向上就能到達(n,n)。為了不跨越y=x,需任意時刻向右的次數>=向上的次數,顯然答案就是卡特蘭數

擴展:幾乎所有的卡特蘭數的問題都可以用這樣的折線法方式解答。比如入棧映射為向右,出棧映射成向上,任意時刻入棧次數>=出棧


例題-luogu P2532 [AHOI2012]樹屋階梯

Problem

Problem

Problem

Problem

分析

卡特蘭數,注意N的取值范圍,要用高精度

Code

#include <cstdio>
#include <iostream>
#define ll long long
using namespace std;
const int maxn=10005;	
struct highprecc{
	int l,a[maxn];
	void init(){l=1;a[1]=1;}
	void out(){for(int i=l;i>=1;i--) printf("%d",a[i]);}
	highprecc operator * (const ll b) const{
		highprecc c;
		for(int i=1;i<=l;i++) c.a[i]=a[i]*b;
		for(int i=2;i<=l;i++){
			c.a[i]+=c.a[i-1]/10;
			c.a[i-1]%=10;
		}
		c.l=l;
		while(c.a[c.l]>10){
			c.a[c.l+1]=c.a[c.l]/10;
			c.a[c.l]%=10;
			c.l++;
		}
		return c;
	}
	highprecc operator / (const ll b) const{
		highprecc c;
		ll k=l,g=0;
		for(int i=l;i>0;i--){
			g=g*10+a[i];
			c.a[i]=g/b;
			g%=b;
		}
		while(k>1 && c.a[k]==0) k--;
		c.l=k;
		return c;
	}
};	
highprecc f(ll n){
	highprecc ans;ans.init();
	for(ll i=n+1;i<=2*n;i++) ans=ans*i/(i-n);
	return ans/(n+1);
}
int main(){
    ll n;scanf("%lld",&n);
    f(n).out();
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM