POJ 1095
#include <iostream> #define MAXN 20 using namespace std; __int64 cat[MAXN]; int sum; void give_catalan(); void dfs(int node,int num); int main() { //freopen("acm.acm","r",stdin); give_catalan(); int n; int i; int sum; while(cin>>n,n) { sum = 0; for(i = 1; sum < n; ++ i) { sum += cat[i]; } -- i; sum -= cat[i]; dfs(i,n-sum); cout<<endl; } } void dfs(int node,int num) { if(node == 1) { cout<<'X'; return; } int i; int j; int sum = 0; for(i = 0; sum < num; ++i) { sum += cat[i]*cat[node-i-1]; } -- i; sum -= cat[i]*cat[node-i-1]; num -= sum; if(i > 0) { cout<<"("; dfs(i,(num-1)/cat[node-i-1]+1); cout<<")"; } cout<<'X'; if(node-1-i > 0) { cout<<"("; dfs(node-1-i,(num-1)% cat[node-i-1]+1); cout<<")"; } } void give_catalan() { int i; int j; cat[0] = 1; cat[1] = 1; for(i = 2; i < 20; ++ i) { cat[i] = 2*(2*(i-1)+1)*cat[i-1]/(i+1); // printf("%d\n",cat[i]); } } /* 定理:n个结点能形成的二叉树总数为 卡特兰数 C(2n,n)/(n+1) 或者由递推公式Ci+1=2*(2*i+1) /(i+2)*Ci 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]; } (2).继续转化问题,这棵树的左子树和右子树各有结点数多少?设这棵树左子树的结点数为i,右子树的结点数为n-i-1, 那么这棵树是又左子树的结点数为i,右子树的结点数为n-i-1的形态的第几种(设为第s种)?可以知道当1<=k<=L[0]*L[n-1]时, 左子树结点树为0,右子树结点数为n-1,s=k;L[0]*L[n-1]+1<=k<=L[1]*L[n-2]时,,左子树结点树为1, 右子树结点数为n-2,s=k- L[0]*L[n-1] ;...当L[i-1]*L[n-i]+1<= L[i]*L[n-i+1]时,左子树结点树为i, 右子树结点数为n-i-1, 。 (3).继续想象s增长的过程即为树形态不断发生变化的过程。那么首先是右子树在发生变化,从1到L[n-i-1]。 继续增长,右子树的形态复位为1,而左子树的形态增加1.因此右子树相当于秒针,左子树相当于分针。 对于s,该树的左子树编号为(s-1)/L[n-i-1]+1,右子树编号为(s-1)% L[n-i-1]+1。 (4).fun(n,k)的递归终止条件很容易知道,为n==1。此时树的形态只有一种,所以直接打印X。 */
关注我的公众号,当然,如果你对Java, Scala, Python等技术经验,以及编程日记,感兴趣的话。
技术网站地址: vmfor.com