正文

Zju 1062 Trees Made to Order2006-08-26 15:17:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/cruxd/17906.html

分享到:

2043646 2006-08-26 14:29:40 Accepted 1062 C++ 00:00.00 432K St.Crux 给出一个N,求中序树形。 Sample Input 120311175320 Sample Output X((X)X(X))X(X(X(((X(X))X(X))X(X))))X(((X((X)X((X)X)))X)X) 这个题的思想是不断逼近。要构造一颗树,(最好)要知道他的左子树序列号和右子树序列号。这个一下子求不出来,但是我们可以先看一下能求出的东西。 N个节点数这儿有几棵树。An= C(2n, n) / (n + 1),这个可以求,打一个表就可。且可求得N<20。 N这整棵树是几个节点。这个就好求了。用An一个一个的依次减,马上就求出来。减出来的数还得存着,待会儿还得减。 左子树几个节点。这个有点技巧了。这要明白一规律,当左子树有l个节点,右子树r个节点时,这样的树有几棵。答案是Al * Ar。这是全题的关键。而且这树是按左子树的节点树依次排下来的。这就好办了,和上面一样,一个一个挨个减下来。算出来以后右子树也出来了。这就是左子树的节点数和右子树的结点数。 最后就是这个序列号了。就拿这4,5,6,7,8来说吧。减到现在,就成了0,1,0,0,1。这有什么规律呢?没错,0,1分别是2号和3号在他们那一组(2棵树的)里的序列号。现在要用数学公式来说的话,就是: 设Sl为左边的序列号(在他们那一组里的,以下同)Sr为右边的,Al是左边节点数树的总个数,Ar同,t是N减到现在还剩的那个数。则可得:Sl = t / Ar, Sr = t  % Ar。因为每棵树是从右开始排,填满了Ar * Al种排法就结束,换到下一种Ar -1的排法里去了,也不归这个排法的管了。左边呢?就Al种排法,一个一个来,比作齿轮的话,就先得让右边的Ar轮一遍,才轮到他动一格。于是这个题就变成简单的排列组合了。 具体的算法边界处还得考虑,这个也是挺麻烦的一个地方。 #include <cstdio> int a[20] = { 1, 1, 2, 5, 14, 42, 132,  429, 1430, 4862, 16796, 58786, 208012,  742900, 2674440, 9694845, 35357670,  129644790, 477638700 }, b[20], n; void dfs(int x){ int s, l, r, i, t = x, xl, xr; for(i = 0; i < 20; i ++) {  if(t < a[i])   break;  t -= a[i]; } s = i - 1; for(i = 0; i <= s; i ++) {  if(t < a[i] * a[s - i])   break;  t -= a[i] * a[s - i]; } l = i, r = s - i; xl = t / a[r] + b[l], xr = t % a[r] + b[r]; if(xl) {  printf("(");  dfs(xl);  printf(")"); } printf("X"); if(xr) {  printf("(");  dfs(xr);  printf(")"); }}  void init(){ int i, t = 0; b[0] = 0; for(i = 0; i < 19; i ++) {  t += a[i];  b[i + 1] = t; }} int main(){ //freopen("in.txt", "r", stdin); init(); while(scanf("%d", &n) && n) {  dfs(n);  printf("\n"); } return 0;}    

阅读(5226) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册