小猴子下落

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

一些小猴子从结点1处开始往下跑,最后一个小猴儿会跑到哪里呢?

输入
输入二叉树叶子的深度D,和小猴子数目I,假设I不超过整棵树的叶子个数,D<=20.最终以 0 0 结尾
输出
输出第I个小猴子所在的叶子编号。
样例输入
4 2
3 4
0 0
样例输出
12
7

给定一棵包含2^d个节点的完全二叉树,如果把节点从上到下从左到右编号为1,2,3,4......
则节点k的左右子节点分别是2k和2k+1。形如:


解法一:不难写出如下模拟程序:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<cstdio>  
  2. #include<cstring>  
  3. const int max = 20;  
  4. int s[1<<20]; //最大节点个数为2^20-1   
  5. int main()  
  6. {  
  7.     int D,I,i,k,n;  
  8.     while(scanf("%d %d",&D,&I)&&(D||I))//d深度,i小球个数   
  9.     {  
  10.         n = (1<<D)-1;  //等同于 n = 2^D-1   
  11.         memset(s,0,sizeof(s));  
  12.         for(i=0; i<I; i++)  
  13.         {  
  14.             k=1;  
  15.             while(1)  
  16.             {  
  17.                 s[k] = !s[k];  
  18.                 k = s[k]?k*2:k*2+1;  
  19.                 if(k>n)  
  20.                     break;  
  21.             }  
  22.         }  
  23.         printf("%d\n",k/2);  
  24.     }  
  25. }  
  26. 注释:a<<20将a的二进制代码左移20位,即a*2*2*...*2(a乘20个二)。  

解法二:
每个小猴都会落在根节点上,因此前两个小猴必然是一个在左子数,一个在右子树。
一般地,只需看小猴编号的奇偶性,就能知道它是最终在哪颗子数中。例如,对于那些
落入根节点左子数的小猴来说,只需知道该小猴是第几个落在根的左子数里的,就可以
知道它下一步往左还是往右了。依次类推,直到小猴落在叶子上。
如果使用题目给出的编号I,则当I是奇数时,它是往左走的第(I+1)/2个小猴,当I时偶数时,
它是往右走的第I/2个小猴。这样,可以直接模拟最后一个小猴的路线。 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<cstdio>  
  2. int main(){  
  3.     int D,I,i,k;  
  4.     while(scanf("%d %d",&D,&I)&&(D||I))  
  5.     {  
  6.         for(i=1,k=1; i<=D-1 ; i++)  
  7.         {  
  8.             if(I&1)  {I = (I+1)/2; k = k*2;}//I是奇数   
  9.             else{I = I/2; k = k*2+1;}  
  10.         }  
  11.         printf("%d\n",k);  
  12.     }  
  13. }  
  14. 注释:I&1将I的二进制与1进行&运算,I是偶数为0,奇数为1.   

这样,程序的运算量就与小猴编号无关了,而且节省了一个巨大的数组。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值