Uva 679 Dropping Balls 解题报告

题目链接 : Dropping Balls

题目大意

第一句话告诉我们这是一个满二叉树,小球从树节点1开始往下掉落,每个树节点会有一个开关,开关初始全部关闭。当每次有小球落在上面时,开关的状态会发生改变。如果小球落到树节点时开关关闭则向左子树走,否则向右子树走。

现在问第i个小球下落到d层时,d层所经过的开关编号。

解题思路

读完题目,首先想到了直接开数组,按照顺序模拟,后来看到I的取值最大到524288,D最大到20,每组数据计算量最高可能到达524288*19=9961472接近1000万,而组数可以有多组。所以不难想到用这个方法应该会超时,所以寻找一下规律。

我们只需要知道小球是第几个落到该树节点的,便可知道小球往左子树还是往右子树。

不难发现,小球到达树节点时,奇数的时候往左子树走,偶数时候往右子树走。对于树节点n,其左子节点为2n, 右子节点为2n+1;

所以我们可以直接模拟第i个球路线,有i个球经过最初的树节点,如果i是奇数往左,偶数往右,然后就有i/2个球分别进入了下一个子树,子树又变成了树节点,然后判断i/2是奇数还是偶数,便可以知道小球往左还是往右,依此类推便可得到第i个球的路线。根据路线便可计算出开关编号。

复杂度分析

时间复杂度为O(n*d)

算法资料

一道思维题

心得体会

看到题目后可以先分析一下想出来的方法可行性,再写题目。

代码

#include 

int main()
{
    int n, d, i, ans;
    while(scanf("%d", &n) != EOF && n != -1)    
    {
        while(n--)
        {
            scanf("%d %d", &d, &i);
            ans = 1;
            for (int j = 1; j < d; j++)
            {
                if(i&1)       			  
                {
                    ans = ans*2;
                    i = (i+1)/2;
                }
                else
                {
                    ans = ans*2+1;
                    i = i/2;
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

你可能感兴趣的:(算法,数据结构,acm竞赛)