您的位置:首页 > 运维架构

(小球下落)Dropping Balls UVA - 679

2018-02-13 07:56 495 查看
题目链接:Dropping Balls UVA - 679

题目:有一颗二叉树,最大深度为D,且所有叶子深度相同,所有结点从上到下、从左到右编号为1,2,3,4,5,….2D−12D−1。在结点1处放一个小球,它会往下落。每个内结点都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否则往右走,知道走到叶子结点,如图所示:



一个小球从结点1依次开始下落,最后一个小球将会落在哪里呢?输入叶子深度D和小球个数I,输出第I个小球最后所在的叶子编号。假设I不超过整棵树的叶子个数。D<=20。输入最多包含1000组数据。

思路:不难发现,对于一个结点kk,其左子结点、右子结点的编号分别是2k2k和2k+12k+1。这个结论非常重要。。。模拟一下。。。

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<iomanip>
#define ll long long

using namespace std;

const int maxn = 20+7;
int s[1<<maxn];

int main()
{
int D,I,t;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&D,&I);
memset(s, 0, sizeof(s));
int k, n = (1<<D) - 1;
for(int i = 0; i < I; i++) {
k = 1;
while(1) {
s[k] = !s[k];
k = s[k] ? 2*k : 2*k + 1;
if(k > n) break;
}
}
printf("%d\n",k/2);
}
return 0;
}


上面的代码TLM了。。。。运算量太大。

每个小球都会落在根结点上,因此前两个小球必然一个在左子树,一个在右子树。一般的只需要看小球编号的奇偶性,就能知道它最终落在哪棵子树中。对于那些落入根结点左子树的小球来说,只需要知道该小球是第几个落在根的左子树里的,就可以知道它下一步往左还是往右了。以此类推,知道小球落到叶子上。

当I是奇数时,它是往左走的第(I+1)/2个小球;当I是偶数时,它是往右走的第I/2个小球。这样就能模拟小球的路线了。

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<iomanip>
#define ll long long

using namespace std;

const int maxn = 20+7;

int main()
{
int D,I,t;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&D,&I);
int k = 1;
for(int i = 0; i < D - 1; i++) {
if(I % 2) { k = 2*k; I = (I+1)/2;}
else {k = k*2 + 1;  I /= 2;}
}
printf("%d\n",k);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: