• hdu 1100 Trees Made to Order


    http://acm.hdu.edu.cn/showproblem.php?pid=1100

      今晚做了一下标记为组合数学的题。这题归类组合数学应该是因为这题用到二叉树计数的原理吧。这次是完全没有参考其他资料的了~

      稍微解释一下题意,这题就是将二叉树标号,然后给出标号,让你画出二叉树来。标号的规则比较长,总的来说就是结点多的标号大,左结点标号大的大,如果左结点标号相同,右结点标号大的大。

      刚开始的时候,我就光靠数字和图形间的关系来推测构图的方法,然后发现要解这题必须要找到根本,就是二叉树计数。然后我就打了个卡特兰数的表,用来关联题目的条件。这时可以找到一个方法来找出左右子树的模样。

      我描述一下方法:因为二叉树计数的递推是依靠左右子树的组合数来产生的,如果按照那种递推方法,将标号不停的减少,最后可以找到左右子树分别有多少个结点。然后,剩余量就是指在该组中是第几种组合方式。接着就是要计算左右子树分别属于它的数量中的第几种组合方式。刚刚说了一下题意,可以发现要右子树变到没得变,左子树才会改变一次,这就是我的代码中取模的操作,得到lrest和rrest。之后的每一个子结点都按照这种方法来找到左右子树的模样,因此我就进行递归的操作。从而得到树的模样!

      最后输出的时候就是一个中序遍历输出,整体基本完成了!

    参考代码:

    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 typedef __int64 ll;
     5 const int maxn = 20;
     6 const ll maxsum = 500000000;
     7 ll tri[maxn << 1][maxn << 1];
     8 ll sum[maxn], rec[maxn];
     9 int cur, l[maxn], r[maxn];
    10 
    11 void build(){
    12     memset(tri, 0, sizeof(tri));
    13     tri[0][0] = 1;
    14     for (int i = 1; i < maxn << 1; i++){
    15         tri[i][0] = 1;
    16         for (int j = 1; j <= i; j++){
    17             tri[i][j] = tri[i - 1][j - 1] + tri[i - 1][j];
    18         }
    19     }
    20     sum[0] = rec[0] = 1;
    21     for (int i = 1; i < maxn; i++){
    22         rec[i] = tri[i << 1][i] / (i + 1);
    23         sum[i] = sum[i - 1] + rec[i];
    24 #ifndef ONLINE_JUDGE
    25         printf("%2d : %12I64d %12I64d\n", i, sum[i], rec[i]);
    26 #endif
    27     }
    28 }
    29 
    30 void con(int rt, int rest, int cnt){
    31     if (rest == 1 && cnt == 1){
    32         return ;
    33     }
    34     cnt--;
    35     for (int i = 0; i <= cnt; i++){
    36         int tmp = rec[i] * rec[cnt - i];
    37 
    38 
    39         if (rest > tmp) rest -= tmp;
    40         else{
    41             int lrest = (rest - 1) / rec[cnt - i] + 1;
    42             int rrest = (rest - 1) % rec[cnt - i] + 1;
    43 
    44             if (i){
    45                 l[rt] = ++cur;
    46                 con(cur, lrest, i);
    47             }
    48             if (cnt - i){
    49                 r[rt] = ++cur;
    50                 con(cur, rrest, cnt - i);
    51             }
    52 
    53             break;
    54         }
    55     }
    56 }
    57 
    58 void print(int rt){
    59     if (~l[rt]){
    60         putchar('(');
    61         print(l[rt]);
    62         putchar(')');
    63     }
    64     putchar('X');
    65     if (~r[rt]){
    66         putchar('(');
    67         print(r[rt]);
    68         putchar(')');
    69     }
    70 }
    71 
    72 void deal(int n){
    73     int cnt = 0;
    74 
    75     while (n >= sum[cnt]) cnt++;
    76 #ifndef ONLINE_JUDGE
    77     printf("%d\n", cnt);
    78 #endif
    79     for (int i = 0; i < cnt; i++)
    80         l[i] = r[i] = -1;
    81     cur = 0;
    82     n -= sum[cnt - 1] - 1;
    83     con(0, n, cnt);
    84     print(0);
    85     puts("");
    86 }
    87 
    88 int main(){
    89     int n;
    90 
    91     build();
    92     while (~scanf("%d", &n) && n)
    93         deal(n);
    94 
    95     return 0;
    96 }

      还是要多做组合数学的题来加快推理的速度啊!

    ——written by Lyon

  • 相关阅读:
    思维导图
    网络面经
    2.17 C++ 专项练习 错题复盘
    C++面经
    2.15 C++专项练习 错题复盘
    uboot下读取flash,上传tftp服务器、下载
    Hi3516EV100烧录出厂固件
    用Hi3518EV200板当spi烧录器
    生而为人,我很抱歉!深夜爬虫, 我很抱歉 ,附微信 “ 网抑云” 公众号爬虫教程!
    阿里HR: 你会 Android 实现侧滑菜单-design吗? CN看了,原来这么简单呀!
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_1100_Lyon.html
Copyright © 2020-2023  润新知