题意:有一颗二叉树,最大深度为D,并且所有叶子的深度都相同。每一个叶子上都有一个开关。初始开关全都是关闭的。节点标 号从左到右,从上到下为1,2,......,2^D-1。结点1处放一个会下落的小球,每次落到叶子上,叶子上的开关就会改变。若开关是关闭的,则小球往左落下;若开关开启,则小球往右落下。
输入树的深度和小球个数,输出第I个小球最后所在的叶子编号。
一开始就感觉就是一个普通的模拟题,开一个容量为2^D-1的数组保存每个叶子上开关的状态即可。
以下是一开始写:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define maxn 20
#define PI 3.1415926536
using namespace std;
int s[1<<maxn];
int main()
{
// std::ios::sync_with_stdio(false);
int d,i,cas,k;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&d,&i);
memset(s,0,sizeof(s));
for(int j=0;j<i;j++)
{
k=1;
while(1)
{
s[k]=!s[k];
k=s[k]?2*k:2*k+1;
if(k>(1<<d)-1)
break;
}
}
printf("%d\n",k/2);
}
return 0;
}
但是事情并没有这么简单。emmm。。。这样开数组由于运算量巨大会导致超时。
还有一种解法,因为开关只有两种状态,关或者开,所以小球不是往左走,就是往右走。
所以,当输入I的时候,可以通过判断I的奇偶性来确定小球的掉落方向。
代码如下:
#include<iostream>
#include<cstdio>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#define maxn 10010
#define PI 3.1415926536
using namespace std;
int main()
{
// std::ios::sync_with_stdio(false);
int cas,d,i,k,j;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&d,&i);
k=1;
for(j=0;j<d-1;j++)
{
if(i%2)
{
k=2*k;
i=(i+1)/2;
}
else
{
k=2*k+1;
i=i/2;
}
}
printf("%d\n",k);
}
return 0;
}