标签:
题目链接:点击打开链接
题目大意:按照图中给的编号方式,节点数逐渐增加,所有的点尽量在右子树上,问第m颗树是什么样子的,按照给的模式输出 (左)x(右),如果没有就缺省。
首先对于n个节点的二叉树一共有多少种形态,这刚好符合卡特兰数的值。
h(n) = C(2n,n)/(n+1) = C(2n,n) - C(2n,n-1) = h(n-1)*(4n-2)/(n+1) (递推公式)。按照递推公式就可以求出对于k个节点二叉树有多少种变化方式。
然后对于求第m颗树,可以先找到第m棵树应该是几个节点,然后找到是给节点数的第几种变化,然后深搜,按照先右后左的顺序,不断累加变化数,找到左右子树都应该是几个节点,第几种变化,然后深搜到下一层。
注意统计变化数的方式,一定是先右子树变化,然后左子树变化,右子树完成所有变化后,左子树的变化加一。
输出方式,按照左根右的输出方式输出。
测试样例:
42
(x(x))x(x(x))
43
(x(x))x((x)x)
44
((x)x)x(x(x))
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; #define LL __int64 #define max1 500000010 LL cat[30] , sum[30] ; struct node{ int l , r ; }p[200] ; int cnt ; void init() { LL i ; cat[0] = cat[1] = 1 ; sum[1] = 1 ; for(i = 2 ; i < 35 ; i++) { cat[i] = cat[i-1]*(4*i-2)/(i+1) ; sum[i] = sum[i-1] + cat[i] ; if( sum[i] >= max1 ) break ; } return ; } void solve(int rt,int m,LL num) { if( m == 0 ) return ; int i , j , temp ; LL ans = 0 , s ; for(i = m ; i >= 0 ; i--) { j = m - i ; if( ans + cat[i]*cat[j] >= num) { num -= ans ; if( i ) { p[rt].r = cnt ; p[cnt].l = p[cnt].r = -1 ; cnt++ ; if( num%cat[i] ) temp = num%cat[i] ; else temp = cat[i] ; solve(cnt-1,i-1,temp) ; } if( j ) { p[rt].l = cnt ; p[cnt].l = p[cnt].r = -1 ; cnt++ ; if( num%cat[i] ) temp = num/cat[i]+1 ; else temp = num/cat[i] ; solve(cnt-1,j-1,temp) ; } break ; } ans += cat[i]*cat[j] ; } return ; } void dfs(int rt) { if( p[rt].l != -1 ) { printf("(") ; dfs(p[rt].l) ; printf(")") ; } printf("X") ; if( p[rt].r != -1 ) { printf("(") ; dfs(p[rt].r) ; printf(")") ; } } int main() { init() ; int n , m , i ; while( scanf("%I64d", &n) && n ) { for(m = 1 ; m < 30 ; m++) if( sum[m] >= n ) break ; cnt = 0 ; p[cnt].l = p[cnt].r = -1 ; cnt++ ; solve(0,m-1,n-sum[m-1]) ; dfs(0) ; printf("\n") ; } return 0; }
版权声明:转载请注明出处:http://blog.csdn.net/winddreams
poj1095--Trees Made to Order(卡特兰数)
标签:
原文地址:http://blog.csdn.net/winddreams/article/details/47828759