紫书刷题进行中,题解系列【GitHub|CSDN】
例题6-6 UVA679 Dropping Balls(23行AC代码)
题目大意
现有一个D层高的满二叉树,小球从根开始向下滚落,直至叶子结点,每个结点有开关标志flag(初值为false),滚落时左右子树选择规则如下
- flag=false:flag置为true,向左子树滚落
- flag=true:flag置为false,向右子树滚落
现求第I个小球落在那个叶子结点
思路分析
直接用静态数组依次模拟I个小球滚落,会超时。因此需要找规律来优化时间,有以下结论:
假设第i个小球Qi是第j个经过结点Vn,可根据j来判断小球下一个走向,若j为偶数,走右子树;否则,走左子树
假设当前结点为根节点,即V1,那么第1个小球走左子树,第二个走右子树,以此类推
假设当前结点为V2,第1,2,3个经过V2的小球为Q1,Q3,Q5,抽象成公式即j=(i+1)/2
假设当前结点为V3,第1,2个经过V2的小球为Q2,Q4,抽象为公式:j=i/2
通过这种方式,可以仅根据I的奇偶性依次判断,时间复杂度为O(logn),并且节省空间
AC代码(C++11,完全二叉树,规律优化)
#include<bits/stdc++.h>
using namespace std;
int T, D, I;
int main() {
scanf("%d", &T);
while (T --) {
scanf("%d %d", &D, &I);
long long ans=1;
for (int i = 1; i <= D-1; i ++) { // 模拟I个小球掉落
if (I % 2 == 1) { // I表示第几个经过当前点
I = (I+1)/2; // 更新
ans *= 2;
}
else { // 偶数走右子树
I /= 2;
ans = ans*2 + 1;
}
}
printf("%lld\n", ans);
}
scanf("%d", &T); // 最后的-1,多余的输入!
return 0;
}