小球下落 !!!
问题描述 :
有一颗二叉树,做大的深度为D,所有叶子的深度都相同,所有节点从上到下从左到右的编号为 1,2,3,4....2^(D-1)
在节点1处放一个小球,他会往下落,每个内节点上都有一个开关,初始化的时候都是关着的,当每次有小球落到一个
开关的时候,他的状态就会变化,当小球到达一个内节点的时候,如果开关是关闭的,就往左走,否则就往右走,直到
走到叶子节点
如图所示 :
D <= 20 输入最多包含1000组数据:
想输入一个D表示二叉树的深度,在输入I表示第几个小球
输出第I个小球最后落入的叶子节点数目
样例 :
4 2
3 4
10 1
2 2
8 128
16 12345
输出:
12
7
512
3
255
36358
问题分析 :
我一开始做的时候就一直没有发现,这个二叉树是有规律的,但是现在发现还是不算太晚的.
任何一个内节点,都有两个子子节点,就像他的两个儿子一样,除了,最后的一行,最后一行不是内节点
这个节点的分布很有意思,任何一个内节点的左子节点都是这个父节点的二倍,(我说的是他们标识的数字)
任何右子节点都是这个父节点而倍加一,如果 父节点上面的数字是,k,这个父节点的左子节点是2*k,这个父节点的
右子节点是2*k+1,有了这个规律解决这个题就方便多了.
伪代码 :
使用动态分配的原则,calloc
建立了n个节点,
1.使用while,while(i < I)
2.num = count ; count = Array[count] == 0 ? 2*count(左节点) : 2*count+1(右节点);
3.Array[num] = Array[num] == 0 ? 1 : 0; //这个就是在遇到小球后开关状态变化
4.if(count*2 > D) {i == I && 输入count;count = 1;i++}
在这里我又一次的使用了 逻辑与操作, 其实这个操作我非常的喜欢,在时间上说,他一定比if要快
而且十分的简单,但是要注意,逻辑与的左右的两条语句必须都要有返回值,如果没有返回值的话
他会报错的.
在这里我使用的动态分配的函数并不是malloc函数,而是calloc函数这个函数其实和
malloc函数差不多,但是使用起来,我感觉还是malloc比较好用,后者之所以我使用他,
是因为使用了这个函数之后就不用初始化了,这个calloc这个函数不用初始化就省去了
一部分的时间开销,其实我想,这部分的时间开销还是存在的,因为你在申请内存的时候
也要进行初始化,这样的话也是花费时间的,不过我实在是懒得写for这样的循环给这个
数组初始化了,这个总的来说这个函数还是有一点优点的......
在linux man手册中 :
void *malloc(size_t size);
void *calloc(size_t nmemb,size_t size);
nmemb是你要申请的空间个数,size是每一个空间占用几个字节
如果实在是看不懂可以看一下他们的介绍,对自己还是有一点帮助的......