• 信息学奥赛一本通 1363:小球(drop)


    【题目链接】

    ybt 1363:小球(drop)

    【题目考点】

    1. 二叉树

    【解题思路】

    该树是满二叉树,深度D最大为20
    第1层有1个结点,第2层有2个结点,…,第D层有 2 D − 1 2^{D-1} 2D1个结点,总结点数量为 1 + 2 + . . . + 2 D − 1 = 2 D − 1 1+2+...+2^{D-1}=2^D-1 1+2+...+2D1=2D1,D最大为20,那么整棵树最大结点数量为 2 20 − 1 = 1048575 2^{20}-1=1048575 2201=1048575

    解法1:链式存储结构二叉树

    结点池大小设为1100000,大于最大结点数量。
    每个结点中保存一个布尔值。
    循环I次,模拟题目描述的过程,小球到一个结点时,如果该结点值为真,该值变为假,走右子树。如果该结点值为假,该值变为真,走左子树。
    记录小球最后落在的叶子结点时的位置。

    解法2:顺序存储结构二叉树

    设bool类型数组tree,大小设为1100000,初值为false。tree[i]表示第i个结点的值。
    第i结点的左孩子编号为2*i,右孩子编号为2*i+1,双亲结点编号为i/2(整除运算)。
    总结点数量为 2 D − 1 2^D-1 2D1,先求出该值记为mx。那么最后一个分支结点为最后一个结点即第mx结点的双亲,为mx/2。
    而后循环I次,p表示当前小球所在的结点编号。如果该结点值为真,该值变为假,走右子树。如果该结点值为假,该值变为真,走左子树。
    最后p的位置即为小球落在的叶子结点的位置。

    【题解代码】

    解法1:链式存储结构二叉树

    #include 
    using namespace std;
    #define N 1100000
    struct Node
    {
        int n, left, right;//n:编号 left, right:左后孩子的地址
    	bool v;//布尔值 
    };
    Node node[N];//结点池 
    int p, D, I, ans;
    int create(int num, int d)//生成值为num的结点的树,根的层次为d 
    {
        if(d > D)
            return 0;
        int np = ++p; 
        node[np].n = num;
        node[np].left = create(2*num, d+1);
        node[np].right = create(2*num+1, d+1);
        return np;
    }
    void fall(int r)
    {
        if(node[r].left == 0 && node[r].right == 0)//如果r是叶子结点 
        {
            ans = node[r].n;//记录最后一次小球落在的叶子结点编号 
            return;
        }
        if(node[r].v)//如果值为真 
        {
            node[r].v = false;//变为假 
            fall(node[r].right);//走右子树 
        }
        else//如果值为假 
        {
            node[r].v = true;//变为真 
            fall(node[r].left);//走左子树 
        }
    }
    int main()
    {   
        cin >> D >> I;
        create(1, 1);
        for(int i = 1; i <= I; ++i)
            fall(1);
        cout << ans;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    解法2:顺序存储结构二叉树

    #include 
    using namespace std;
    bool tree[1100000];//顺序存储结构二叉树 初始值为false
    int main()
    {
        int mx, D, I, p;//p为此时指向的结点在数组中的下标 第1位置是树的根
        cin >> D >> I;
        mx = int(pow(2, D))-1;
    	for(int i = 1; i <= I; ++i)
        {
            p = 1;
            while(p <= mx/2)//叶子结点那一层不用计算
            {
                if(tree[p])
                {
                    tree[p] = false;
                    p = 2 * p + 1;//走右子树
                }
                else
                {
                    tree[p] = true;
                    p = 2 * p;//走左子树
                }
            }
        }
        cout << p;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
  • 相关阅读:
    产品经理如何做项目管理?
    从零开始学习Dubbo7——Dubbo的高级特性
    x86_64、AArch64、ARM32、LoongArch64、RISC-V
    【红外与可见光图像融合】离散平稳小波变换域中基于离散余弦变换和局部空间频率的红外与视觉图像融合方法(Matlab代码实现)
    浅谈基于云计算的环境智能监控系统
    通过python操作neo4j
    C语言:如何给全局变量起一个别名?
    依概率收敛和依分布收敛(附一道例题)
    佳博打印机打印条码和二维码的方法
    【代码精读】optee的异常向量表
  • 原文地址:https://blog.csdn.net/lq1990717/article/details/126309056