小球下落

来源:互联网 发布:后端 知乎 编辑:程序博客网 时间:2024/04/26 20:59

【描述】

        有一棵二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右编号为1,2,3,...,2^D-1。在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,它的状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否者往右走,直到走到叶子结点。如下图所示


        一些小球从结点1处依次开始下落,最后一个小球将会落到哪里呢?输入叶子深度D和小球个数I,输出第I个小球最后所在的叶子编号。假设I不超过整棵树的叶子个数(即2^(D-1))。D<=20。输入最多包含1000组数据。
样例输入:
4 2
3 4
10 1
2 2
8 128
16 12345
样例输出:
12
7
512
3
255

36358

【分析】

观察不难发现对于满二叉树而言,父节点和子节点的关系是k,2k,2k+1的关系,在不求效率的前提下我们可以直接模拟全部小球的整个过程,定义一个超大数组,然后又小球经过就给他取相反数。最后就可以得到最后一个小球的下落点。但是这里给出的数据是d<=20,就意味着有2^19个叶子节点,如果再1000组数据……另外,由于二叉树是一开一关一开一关,因此我们只需要知道小球是经过该节点的奇数个还是偶数个就知道小球下一次去向的是左子树还是右子树,同样的,在对小球进入的下一个节点做判断,如果是偶数则往右子树,直到没有子节点。因此题目要求最后一个小球的落点,我们只需要模拟最后一个小球的路劲就好,只要知道最后一个小球相对于每个节点而言是基数还是偶数就知道下一步是往左还是往右,这里需要注意的是小球每次相对于每一个节点而言是不一样的。比如说i是奇数,则小球相对于第一个节点而言是往左走的第(i+1)/2个小球,然后对于第一个节点的左子树而言则需要判断第(i+1)/2相对于它而言是奇数还是偶数。

【代码】

#include<iostream>using namespace std;int main(){freopen("ball.in","r",stdin);freopen("ball.out","w",stdout);int D,I;int k,i;while(scanf("%d%d",&D,&I)==2){i=D;k=1;while(i>1){if(I%2==1){k=2*k;I=(I+1)/2;}else{k=2*k+1;I=I/2;}i--;}cout<<k<<endl;}fclose(stdin);fclose(stdout);return 0;} 

ball.in


ball.out




0 0