• UVa 679


    题目链接

    题目大意:

    小球从一棵所有叶子深度相同的二叉树的顶点开始向下落,树开始所有节点都为0。若小球落到节点为0的则往左落,否则向右落。并且小球会改变它经过的节点,0变1,1变0。给定树的深度D和球的个数I,问第I个小球会最终落到哪个叶子节点。

    解题思路:

    完全二叉树有一个重要的性质:对于任意一个节点k,其左节点、右节点的编号分别为2k和2k+1

    对于根节点,很容易知道当球的编号为奇数时,球落入左子树,偶数时落在右子树。这样其实对于其它节点看成根节点时也是一样的。比如对于第7个球,为奇数,是第7个到达一号节点的球,也是第(7/2)+1=4个到达2号节点球,再往下也是第2个到达5号节点的球。。。。

    所以可以直接通过找规律,模拟最后一个球的判断过程

    这是我的AC代码

    #include <cstdio>
    typedef long long ll;
    ll d, n;
    
    int main()
    {
        int cur;
        while (scanf("%d", &cur) != EOF,cur!=-1)
        {
            while (cur--)
            {
                scanf("%lld%lld", &d, &n);
                int height = 1;
                ll num = 1;
                while (height < d)                    //从深度为1的根节点到达深度为d的叶子总共需要判断d-1次
                {
                    if (n % 2 == 0)                    //当球的编号为偶数的时候
                    {
                        num = num * 2 + 1;
                        n = n / 2;
                        height++;
                    }
                    else                               //当球的编号为奇数的时候
                    {
                        num = num * 2;
                        n = (n + 1) / 2;
                        height++;
                    }
                }
                printf("%lld
    ", num);
            }
        }
        return 0;
    }

    以下更为精简的代码,和两种思路

    数学思路

    #include<stdio.h>
    
    int main()
    {
        int D, I,cas;    
        while (scanf("%d", &cas) != EOF,cas!=-1)
        {
            while (cas--)
            {
                scanf("%d%d", &D, &I);
                int k = 1;
                for (int i = 0; i < D - 1; i++)
                {
                    if (I % 2)                  //奇数
                    {
                        k = 2 * k;
                        I = (I + 1) / 2;
                    }
                    else {
                        k = 2 * k + 1;
                        I = I / 2;
                    }
                }
            printf("%d
    ", k);
            }
        }
        return 0;
    }

    模拟下落过程

    #include<stdio.h>
    #include<string.h>
    const int MAXD = 20;
    int s[1<<MAXD];  //最大节点个数 2^MAXD - 1
    
    int main()
    {
        int D, I,cas;
        while (scanf("%d", &cas) != EOF,cas!=-1)
        {
            while (cas--)
            {
                scanf("%d%d", &D, &I);
                memset(s, 0, sizeof(s));  //开关初始全0,表示关闭
                int k, n = (1 << D) - 1;    //k表示下落到的节点的开关下标
                for (int i = 0; i < I; i++)    //共下落I个小球
                {
                    k = 1;
                    while (1)
                    {
                        s[k] = !s[k];
                        k = s[k] ? 2 * k : 2 * k + 1;  //根据开关选择左右子树
                        if (k > n) break;  //落到树外,出界
                    }
                }
                printf("%d
    ", k / 2); //出界前叶子节点编号
            }
        }
        return 0;
    }

    2018-03-31


    作者:is_ok
    出处:http://www.cnblogs.com/00isok/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    经济--股票--深圳指数基金
    经济--年终奖理财攻略
    经济--股票--基金经理打死不肯说的赚钱黑幕
    经济--股票--基金定投
    经济--股票--基金分类的三个角度
    经济学--股票--必胜法则
    经济--降息对股市是好消息还是坏消息?
    PHP数组的排序函数
    使用回调函数处理数组的函数
    统计数组元素的个数和唯一性的函数
  • 原文地址:https://www.cnblogs.com/00isok/p/8683488.html
Copyright © 2020-2023  润新知