UVa 679 【思维题】

UVA 679

紫书P148例题。

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

题意容易理解,紫书上给了一个模拟的做法,但这样会超时。后面的想法我觉得很巧妙。

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

所以可以直接模拟最后一个球:

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=20;
 6 int s[1<<20];
 7 
 8 int main()
 9 {
10     int T;
11     cin>>T;
12     int D,I;
13     while(scanf("%d",&D))
14     {
15         if(D==-1) break;
16         scanf("%d",&I);
17         int k=1;
18         for (int i=0;i<D-1;i++)//从根节点开始只需走D-1次
19         {
20             if(I&1){    //是奇数号球
21                 k=k*2;  //就往左子树走
22                 I=(I+1)/2;  //相当于是经过当前结点的第(I+1)/2个球,用来判断下回球往哪走
23             }else{     //是偶数号球
24                 k=k*2+1;    //就往右子树走
25                 I/=2;   //相当于是经过当前节点的第(I/2)个球,用来判断下回球往哪走
26             }
27         }
28         cout<<k<<endl;//输出球到的位置
29     }
30     return 0;
31 }

 

 

也有人从哈夫曼编码角度理解,结果正好是I-1的二进制逆序,感觉很厉害!

 

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=20;
int s[1<<20];

int main()
{
    int T;
    cin>>T;
    int D,I;
    while(scanf("%d",&D))
    {
        if(D==-1) break;
        scanf("%d",&I);
        int k=1;//k初始化为1,即最高位为1
        I-=1;   //求I-1的二进制逆序:
        while(--D)
        {
            if(I&1){
                k=(k<<1)+1;
            }else{
                k<<=1;
            }
            I>>=1;
        }
        cout<<k<<endl;
    }
    return 0;
}

 

posted @ 2017-08-03 09:02  ╰追憶似水年華ぃ╮  阅读(428)  评论(0编辑  收藏  举报