UVA 679 - Dropping Balls (小球下落) By SuCicada

例题6-6 小球下落(Dropping Balls, UVa 679)
有一棵二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右
编号为1, 2, 3,…, 2D-1。在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,
初始全部关闭,当每次有小球落到一个开关上时,状态都会改变。当小球到达一个内结点
时,如果该结点上的开关关闭,则往左走,否则往右走,直到走到叶子结点,如图所
示。
UVA 679 - Dropping Balls (小球下落) By SuCicada_第1张图片
一些小球从结点1处依次开始下落,最后一个小球将会落到哪里呢?输入叶子深度D和
小球个数I,输出第I个小球最后所在的叶子编号。假设I不超过整棵树的叶子个数。D≤20。
输入最多包含1000组数据。
样例输入:
6
4 2
3 4
10 1
2 2
8 128
16 12345
-1
样例输出:
12
7
512
3
255
36358

本家链接


  1. 最简单能想到的就是模拟,模拟球的下落,但是输入一旦大了就超时了。
  2. 所以我们可以,找规律。

首先假设有6层,我们来扔球看看情况

球数   落下位置(最后一行,第一个为0计数)
    0     0
    1    16
    2     8
    3    24

    4     4
    5    20
    6    12
    7    28

    8     2
    9    18
   10    10
   11    26

   12     6
   13    22
   14    14
   15    30
---
   16     1
   17    17
   18     9
   19    25
   20     5
   21    21
   22    13
   23    29

   24     3
   25    19
   26    11
   27    27
   28     7
   29    23
   30    15
   31    31

==== 第33开始轮回 ===

   32     0
   33    16
   34     8
   35    24
   36     4
   37    20
   38    12
   39    28

发现规律了吧。
因为按照扔球数量,32为一个大轮回,这缘于底层数32。
再次基础上我们可以按照16个一组进行再分组,然后可见第二组比起第一组,相对扔球数的结果位置数字要大1。比如:17球结果17,比1球结果16,结果大1。23球结果29,比7求结果28,大1。
然后我们再次更小尺度分组,8个一组,可见后一组的结果位置数大前一组2。

总结规律如下:

底层数量 分组按照的大小 当前尺度的分组的答案偏移量
N M P
32 16 1
8 2
4 4
2 8
1 16

所以假设要求30球的值,就是

首先减一,对齐从0开始: 30 - 1

被减数 组大小 组对应的偏移值
29 16 1
13 8 2
5 4 4
1 1 16
0 0

res = (1+2+4+16) + 2^5(底层数) = 23 + 32 = 55


所以公式如下:

假设层数d,球数n

T ( m , 0 ) = 0 T(m,0)=0 T(m,0)=0
T ( n , d ) = ( T ( ⌊ ( n / 2 ) ⌋ , d − 1 ) + ( n m o d    2 ) ) × 2 T(n,d) = (T(\lfloor (n/2) \rfloor,d-1) + (n \mod 2) ) \times 2 T(n,d)=(T((n/2),d1)+(nmod2))×2
或者用循环表示

res = 0
for ( i = 0 to d ):
	res  = res * 2 + mod(n,2)  
	n  = floor(n / 2)

代码

#include
#include
#include
#include
using namespace std;
int main()
{
     
    int T;
    cin>>T;
    while(T--){
     
        int depth,index;
        cin>>depth>>index;
        int res = 0;
        int bottom = pow(2,depth-1);    // 底层数量
        int waitReverse = (index-1) % bottom; 
        for(int i=0;i<depth-1;i++){
     
            res <<= 1;                  // 乘 2
            res += (waitReverse & 1);   // 模2, 取奇偶
            waitReverse >>= 1;          // 除2, 向下取整 
        }
        cout<<res + bottom<<endl;
    }
    int end;
    cin>>end;
    return 0;
}
// AC at 2020/03/11

ps:拖了4个月了。再拖下去我就没了。

你可能感兴趣的:(UVA 679 - Dropping Balls (小球下落) By SuCicada)