POJ 1095 卡特蘭數+dfs
感覺和上次codeforce的第四題有點像,雖然沒做出來,呵呵。
看來枚舉左右子樹這一招還是蠻常用的。其實我本來想練下卡特蘭數的,結果變成練DFS了。
注意遞歸求解左右孩子時的那兩個參數,一定要先加上1,否則就不對了。
#include<stdio.h>
long long a[20];
long long b[20];
//定理:n個結點能形成的二叉樹總數為 卡特蘭數 C(2n,n)/(n+1) 或者由遞推公式Ci+1=2*(2*i+1)/(i+2)*Ci
//設計figure(n),n代表這棵樹整體的偏移量
//分別算出其左右子樹各自的偏移量,遞歸求解即可
//由于先遞歸左兒子,輸出順序與題意相符
void figure(int n) 

{
int t,i,j; 
if(n==1)
{printf("X");return;}
j=0;
while(true) if(b[++j]>=n) break;
n=n-b[j-1];//j代表有幾個結點,n此時代表在這些結點下的序號
for(i=0;i<j;i++) 
{
t=a[i]*a[j-1-i];
if(t>=n) break;
else n=n-t;
}
if(i!=0) //i是此時左子樹掛的節點數
{
printf("(");
figure(b[i-1]+1+(n-1)/a[j-1-i]);//初始的時刻,只需要增加1,左子樹的偏移量就增加1,而之后的部分,需要右子樹變換a[j-i-1]次,左子樹的偏移量才增加1
printf(")");
}
printf("X");
if(i!=j-1) 
{
printf("(");
figure(b[j-2-i]+1+(n-1)%a[j-1-i]);
printf(")");
}
}
int main() 

{
int n;
int i,j;
a[0]=1;
a[1]=1;
b[1]=1;
b[0]=0;
for(i=2;i<20;i++) 
{
a[i]=2*(2*(i-1)+1)*a[i-1]/(i+1) ;//卡特蘭數遞推公式
b[i]=b[i-1]+a[i];
}
while(scanf("%d",&n)&&n) 
{
solve(n);
printf("\n");
}
return 0;
} 
posted on 2010-04-13 17:33 abilitytao 閱讀(2164) 評論(5) 編輯 收藏 引用

