• 详细讲解Codeforces Round #624 (Div. 3) E. Construct the Binary Tree(构造二叉树)


    题意:给定节点数n和所有节点的深度总和d,问能否构造出这样的二叉树。能,则输出“YES”,并且输出n-1个节点的父节点(节点1为根节点)。

    题解:n个节点构成的二叉树中,完全(满)二叉树的深度总和最小,单链树(左/右偏数)的深度总和最大。若d在这个范围内,则一定能构造出来;否则一定构造不出来。

        1.初始构造一颗单链树,依次把底部的节点放入上面的层,直到满足深度总和为d

        2.若当前深度总和sum > d,则先拿掉底端节点。

          拿掉后,若sum依然比d大,就直接把底端节点放入有空位的最上层;

          拿掉后sum <= d,dif = d - sum。

            若dif >= 此时有空位的最上层深度,则深度为dif的层一定有空位,把底端节点放入该层,即可完成构造。

            否则,依然把底端节点放入有空位的最上层,修改后的sum依旧比d大,继续循环即可。

        3.退出循环后就完成了构造,获得了所求的树。

    具体存储结构、表示方式和算法过程见代码(和注释):

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 /*
     5 9 21
     6 YES
     7 1 1 2 2 4 4 6 8
     8 9 22
     9 YES
    10 1 1 2 2 4 6 6 7
    11 */
    12 int layer[5005], num[5005];    //layer[i]先存第i+1个点所在层的深度,num[i]是深度为i的层里的节点数
    13 
    14 int main() {
    15     int t, n, d;
    16     scanf("%d", &t);
    17     while (t--) {
    18         scanf("%d%d", &n, &d);
    19         memset(num, 0, sizeof num);
    20         int sum = n * (n - 1) / 2, dep = 0, minn = 0;
    21         num[0] = 1;        //0深度层只有一个根节点
    22         for (int i = 2; i <= n; i++) {
    23             //i&(i - 1)的结果为把i二进制下最后一个1置0。i&(i - 1) == 0时,i为2的整数次幂
    24             if ((i&(i - 1)) == 0)dep++;        //第i+1层的第一个节点为2^i
    25             minn += dep;                    //minn记录满二叉树时的深度总和
    26 
    27             layer[i - 1] = i - 1;    //单链树时,和为sum,layer[i]是第i+1个点所在层的深度
    28             num[i - 1] = 1;            //num[i]记录深度为i的层的节点总数
    29         }
    30         if (d<minn || d>sum) {
    31             puts("NO");
    32             continue;
    33         }
    34         puts("YES");
    35         dep = 1;    //当前有空位的最上层的深度
    36         for (int i = n - 1; i > 0 && sum > d; i--) {
    37             sum -= i;        //拿掉底端顶点
    38             num[i]--;
    39             if (sum > d) {            //拿掉之后,sum仍然比d大时;直接放最上面
    40                 layer[i] = dep;        //第i+1个点现在的深度为dep
    41                 sum += dep;
    42 
    43                 if (++num[dep] == (1 << dep))dep++;    //若最上面的层满了,修改为下一层
    44             }
    45             else {                    //拿掉之后,sum<=d时
    46                 int dif = d - sum;        //看差值对应的层是否有空位
    47                 if (dif >= dep) {            //有空位,则直接放到深度等于差值的那一层,构造成功
    48                     layer[i] = dif;
    49                     sum += dif;    //写出来更好理解
    50                     num[dif]++;    //该层节点数++
    51                     break;
    52                 }
    53                 else {                        //无空位,只能放最上面dep层
    54                     layer[i] = dep;
    55                     sum += dep;                //此时sum仍然 > d
    56                     if (++num[dep] == (1 << dep))dep++;    //若最上面的层满了,修改为下一层
    57                 }
    58             }
    59         }
    60         //构造成功。layer[i]是原来单链树中深度为i的点(第i+1个点) 现在的深度,num[i]是第i层的节点总数
    61         //现只用num中的信息求解;layer中的信息只是辅助理解,现在用来存最终答案(即第i个节点的父节点编号)
    62         int id(2), fid(1);    //当前节点编号,上一层首个节点的编号
    63         for (int i = 1; num[i]; i++) {    // while(深度为i的层节点数不为0)
    64             for (int j = 0; j < num[i]; j++) {
    65                 //深度为i的层的第j个节点,在完全二叉树中的编号为(1<<i)+j,上一层首个节点编号为1<<(i - 1)
    66                 //layer[id++] = fid + ((1 << i) + j) / 2 - (1 << (i - 1)); 直接算这个式子会溢出
    67                 layer[id++] = fid + j / 2;    //简化后得出,也可以直接理解推出来
    68             }
    69             fid += num[i - 1];
    70         }
    71         for (int i = 2; i < n; i++)
    72             printf("%d ", layer[i]);
    73         printf("%d
    ", layer[n]);
    74     }
    75     return 0;
    76 }

    完全二叉树编号:

              1

        2            3

     4     5      6      7

    8  9  10  11  12  13  14  15 

  • 相关阅读:
    Linux学习——在虚拟机上的Linux进行磁盘分区
    Linux命令学习3——用户管理
    linux 命令学习2
    linux 命令学习1——tr命令
    基于netty的一个简单的时间服务器的实现(netty学习)
    JavaNIO
    JavaNIO中的内存映射io
    打造高效的工作环境 – SHELL 篇
    linux下怎么清理缓存
    清理系统缓存
  • 原文地址:https://www.cnblogs.com/zsh-notes/p/12372817.html
Copyright © 2020-2023  润新知