题解 UVA679 【小球下落 Dropping Balls】
james1BadCreeper · · 题解
这道题可以用来二叉树入门。
这是一棵满二叉树。不难发现对于任意编号节点
例如上图的节点
这样,不难写出如下模拟程序。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX=(1<<20)+10;
int pr[MAX],tot;
bool s[MAX];
inline int read(void)
{
register int x=0;
char ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
inline void print(int x)//非递归能快一些
{
tot=0;
while(x)
{
pr[++tot]=x%10;
x/=10;
}
while(tot)
putchar(pr[tot--]+'0');
puts("");
}
int main(void)
{
register int now,i,T=read();
int d;
while(T--)对于每组数据
{
d=read();
i=read();
memset(s,0,sizeof(s));//清空数组
int n=(1<<d)-1;//n是最大节点编号
while(i--)
{
now=1;
while(now<=n)
{
s[now]=!s[now];//模拟变化状态
now=(s[now]?(now<<1):(now<<1|1));//进行移动
}
}
print(now>>1);
}
read();//小心-1碍事
return 0;
}
由于
由于每个小球必定会落在根节点(最初节点),因此前两个小球必然一个在左子树,一个右子树。所以,一般地,我们可以递归地执行此操作,只需要看小球的奇偶性,就能判断小球落在哪棵子树上。
所以,当
(这里不懂的话可以自行手玩样例,基本上就懂了)
register int now=1;
for(register int k=0;k<d-1;k++)//层数进行循环
if(i%2==1) //奇数
now*=2,i=(i+1)/2; //左移
else //偶数
now=now*2+1,i/=2; //右移
print(now);
这是部分代码,完整代码在这里~:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAX=(1<<20)+10;
inline int read(void)
{
register int x=0;
char ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
void pr(int x)
{
if(x>9) pr(x/10);
putchar(x%10+'0');
}
inline void print(int x)
{
pr(x);
puts("");
}
int main(void)
{
register int T=read(),i;
int d;
while(T--)
{
d=read();
i=read();
register int now=1;
d--;
for(register int k=0;k<d;k++)
i&2-1?(now<<=1,i=(i+1)>>1):(now=(now<<1)|1,i>>=1);//卡常技巧
print(now);
}
read();
return 0;
}