小球二叉树下落

来源:互联网 发布:js跨域解决什么问题 编辑:程序博客网 时间:2024/04/30 09:56

网上的主流解法是利用奇偶判断小球的走向,由于是满二叉树,左拐或者右拐的后的编号是可以计算的,由此就算出了最终的答案。

本篇博客的具体题目稍有不同,但题意相同。

题目链接:http://oj.acmclub.cn/problem.php?cid=1157&pid=3

题目描述(链接是竞赛模块,去问题模块找吧)
有一颗满二叉树,最大深度为D,所有叶子的深度都相同。所有结点从上到下从左到右的编号分别依次是1,2,3,4,~,(2的D次方-1)。
在结点1放下一个小球,它会往下落。每个结点都有一个状态(开或关)。初始时,每个结点都处于关状态,当小球经过一个结点时,开关状态会改变:当结点为关状态时,小球向左落下,同时结点状态变为开;当结点为开状态时,小球向右落下,同时结点状态变为关。小球一直下落,直到走到叶子结点。输出第K个小球落到的结点的编号。

输入
一个深度D,以及多个K(多组输入)

输出
对于每个K,输出第K个小球落到的叶子结点的结点编号

样例输入
4
9
3
6
样例输出
8
10
13

我的想法是,既然是二叉树,联想到二进制。用二进制记录球在到达底部时路上的转向,1 表示左转,0表示右转。观察知,对一个四层的满二叉树,扔 8 次球。相应的 01 串为:000,100,010,110,001,101,011,111。将这些 01 串转换成对应的十进制数,发现正是终点结点相对于同一层最左端结点的偏移量。怎样可以计算出这些 01 串呢?如果将这些串的最左边一位做为最低位,可以发现,这些串的数值变成了 0,1,2,3,4,5,6,7,等于K的值减 1。另外可以观察出,最后到达的位置是按照周期变化的,周期长度就是最后一层结点的数目。
#include <iostream>using namespace std;int num[21];  //打表记录2的幂int main() {num[20] = 1;for (int i = 19;i >= 0;--i)num[i] = 2 * num[i + 1];int d, k;cin >> d;while (cin >> k) {int pos = 21 - d, ans = num[pos];//此时ans等于最后一层的结点数, 也等于前 n-1 层结点数的和加 1--k;k %= ans; //用周期取模while (k) {++pos;if (k & 1)ans += num[pos]; //将二进制还原成十进制k >>= 1;}cout << ans << "\n";}return 0;}