小猴子下落
-
描述
-
有一颗二叉树,最大深度为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
1.
//简单模拟 #include <iostream> #include <cstring> using namespace std; int h, n; bool vis[10000000]; int pos; int main() { while (cin >> h >> n, h + n){ memset(vis, 0, sizeof(vis)); for (int i = 0; i < n; i++){ pos = 1; for (int j = 0; j < h - 1; j++){ if (vis[pos] == 0){ vis[pos] = 1; pos = pos * 2; } else{ vis[pos] = 0; pos = pos * 2 + 1; } } } cout << pos << endl; } return 0; }
2.讲一下优化算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 根据右图测试数据可知,一共有n行(3,4,5),x个猴子中每2^n出现一循环,理由就是它是满二叉树。
根据左图四层我们列出数据看看:
第1只猴子 1 2 4 8 第2只猴子 1 3 6 12 第3只猴子 1 2 5 10 第4只猴子 1 3 7 14 第5只猴子 1 2 4 9 第6只猴子 1 3 6 13 第7只猴子 1 2 5 11 第8只猴子 1 3 7 15 请读者看看四层二叉树(上左图)和上表中对比不难发现,进入第n个结点的次数i为奇数(即前面已有n-1过猴子访问过该结点),那么遍历其左子树根;
若为偶数,则遍历其右子树根。
因此,对照上表,得出规律:i为奇数,k=k*2;i=(i+1)/2;//第i个进入左子树
i为偶数,k=k*2+1;i=i/2; //第i个进入右子树
例如
第1个猴子:则对于第一个结点来说,i=1为奇数,那么下一个要走的结点k=1*2=2;然后i=(1+1)/2=1(第一个进入左子树),继续判断其左子树i的奇偶性……
第3个猴子:则对于第一个结点来说,i=3为奇数,那么下一个要走的结点k=1*2=2;然后i=(3+1)/2=2(第二个进入左子树)……
第5个猴子:则对于第一个结点来说,i=5为奇数,那么下一个要走的结点k=1*2=2;然后i=(5+1)/2=3(第三个进入左子树)……
……
1 for (int j=0;j<d-1;j++) 2 if(i%2) {k=k*2;i=(i+1)/2;} 3 else {k=k*2+1;i /=2;}
接着按照输入标准写出完整算法如下:
#include <iostream> #include <cstring> using namespace std; int h, n, pos; int main() { while (cin >> h >> n, h + n){ pos = 1; for (int i = 0; i < h - 1; i++){ if (n % 2){ //左子树 pos = pos * 2; n = (n + 1) / 2; //第n个进入左子树 } else{ //右子树 pos = pos * 2 + 1; n = n / 2; //第n个进入右子树 } } cout << pos << endl; } return 0; }