Dropping Balls UVA - 679 (二叉树 思维)
题意:
给出深度为D的儿二叉树, 所有叶子的深度都相同, 每一个节点有一个开关, 节点编号规则如图
在1处放一个小球, 如果该节点关闭往左走, 否则往右走, 每次经过节点改变节点开关状态, 求第I个小球从哪个节点出来
题解:
这道题的树比较稠密, 可以用数组来存, 比较容易想到的算法就是遍历I次, 模拟小球的下落, 最终看出口在哪, 如下代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const LL maxn = 1<<20;
bool t[maxn]; //最大节点为2*20-1个
int I, D, T;
int drop(){
//模拟小球下落的过程并返回最后所在叶子编号
int cur = 1;
while(cur <= (1<<(D-1)) -1){
if(!t[cur*2])
t[cur*2]^=1, cur = cur*2;
else
t[cur*2+1]^=1, cur = cur*2+1;
}
return cur;
}
int main()
{
cin >> T;
while(T--){
cin >> D;
if(D==-1) break;
cin >> I;
ms(t, 0);
for(int i = 1; i <= I; i++){
if(i==I) cout << drop() << endl;
else drop();
}
}
return 0;
}
上面的代码交上去会TLE, 因为时间复杂度过大了, 下面引用一下紫书的讲解.
从小球的行走过程中可以找到规律, 通过二叉树只有左右和奇偶性来判断的
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef long long LL;
const LL maxn = 1<<20;
int I, D, T;
int main()
{
cin >> T;
while(T--){
cin >> D;
if(D==-1) break;
cin >> I;
int k = 1;
for(int i = 0; i < D-1; i++){
if(I%2)
k*=2, I = (I+1)/2;
else
k = k*2+1, I/=2;
}
cout << k << endl;
}
return 0;
}