小球下落-二叉树

来源:互联网 发布:手机号码数据库腾讯 编辑:程序博客网 时间:2024/04/29 16:23

有一颗二叉树,最大深度为D,所有叶子的深度都相同。所有结点从上到下从左到右的编号分别依次是1,2,3,4,~,(2的D次方-1)。在节点1放下一个小球,它会往下落。每个内结点都有一个状态(开或关),初始时,每个内结点都处于关闭状态,当小球经过一个内结点时,开关状态会改变。当为开状态时,小球向左落下;当为关状态时,小球向下落下,直到走到叶子结点。

输出树的深度D,和小球数量I

输出第I个小球落到的结点编号

输入样例: 

4 2

3 4

2 2

16 12345

输出样例:

12

7

3

36358

模拟全过程:

#include<stdio.h>#include<string.h>const int maxn=20;int s[1<<maxn];   //最大节点个数为2^maxn-1int main(){    int D,I;    while(scanf("%d%d",&D,&I)==2)    {        memset(s,0,sizeof(s));     //开关        int k,n=(1<<D)-1;    //n是最大节点编号        for(int i=0; i<I; i++) //连续让I个球下落        {            k=1;            for(;;)            {                s[k]=!s[k];                k=s[k]?k*2:k*2+1;    //根据开关状态选择下落方向                if(k>n)         //已经落“出界”了                    break;            }        }        printf("%d\n",k/2);    //出界之前的叶子编号    }    return 0;}

找规律:

当I是奇数时,它是往左走的第(I+1)/2个小球;当I是偶数时,她是往右走的第I/2个小球。这样,可以直接模拟最后一个小球的路线:

如果I是奇数,它一定会落在左子树,否则,一定是在右子树。以I为3为例,可以将它看作是从节点2开始降落的第二个球,依此类推。

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

From:《算法竞赛入门经典》
0 0
原创粉丝点击