小球下落
【题目大意】
           有一颗二叉树,最大深度为D,且所以叶子的深度都相同。所有结点从上到下       从左到右编号为1,2,3,....2^D-1.在结点1处放一个小球,他会往下落。每个内结点       上都有一个开关,初始全部关闭,当每次有小球落到一个开关时,状态会发生改         变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否则往右         走,直到走到叶子结点。如下图
【分析】
先将每个结点用数组保存标记,几个小球下落,就执行几次循环,每次执行,凡是到了哪个结点处就使 标记数组变化,使其下次可以指到不同的方向。
【代码实现】
代码 1:
#include<stdio.h>
#include<string.h>
const int maxd=20;
int s[1<<maxd];  // 表示2^maxd,1的二进制数向左移动maxd位,即在1的二进制后面加了maxd个0
int main()
{
    int D,I;
    while(~scanf("%d %d",&D,&I))    // 输入叶子所在的深度D,和有多少个小球下落
    {
        memset(s,0,sizeof(s));
        int k,n=(1<<D)-1;       // n为最大结点编号
        for(int i=0;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;
}
这个代码简单但数据太大就会超时,很适合了解小球下落的过程
代码 2:
#include<stdio.h>
#include<string.h>
int main()
{
    int D,I;
    while(~scanf("%d %d",&D,&I))
    {
        int k=1;
        for(int i=0;i<D-1;i++)  // 有D层,就遍历D次
            if(I%2)         // I个小球到每一层时,只考虑第I个就行了,如果它为奇数它就往左走,如果它为偶数他就往右走
        {
            k=k*2;
            I=(I+1)/2;
        }
        else
        {
            k=k*2+1;
            I/=2;
        }
        printf("%d\n",k);
    }
    return 0;
}
/*
输入:
4 2
3 4
10 1
2 2
8 128
16 12345
输出:
12
7
512
3
255
36358
*/
原文:http://blog.csdn.net/disparity_cjk/article/details/51328545