http://acm.nyist.net/JudgeOnline/problem.php?pid=63
小猴子下落
时间限制:
3000 ms | 内存限制:
65535 KB 难度:
3
- 描述
有一颗二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从左到右从上到下的编号为1,2,3,·····,2的D次方减1。在结点1处放一个小猴子,它会往下跑。每个内结点上都有一个开关,初始全部关闭,当每次有小猴子跑到一个开关上时,它的状态都会改变,当到达一个内结点时,如果开关关闭,小猴子往左走,否则往右走,直到走到叶子结点。
一些小猴子从结点1处开始往下跑,最后一个小猴儿会跑到哪里呢?
- 输入
- 输入二叉树叶子的深度D,和小猴子数目I,假设I不超过整棵树的叶子个数,D<=20.最终以 0 0 结尾
- 输出
- 输出第I个小猴子所在的叶子编号。
- 样例输入
4 2 3 4 0 0
- 样例输出
12 7
//类型:满二叉树的建立与遍历
//题意:一颗高度为H的满二叉树,每个节点从左到右从上到下依次编号1,2,3...2^H-1,
//开始设每个节点都是关闭的,然后有N个猴子从根节点开始按照一定的规则往下走。
//(规则:到一个节点,若该节点是关闭的,将该节点打开,同时往左走,
// 若该节点是打开的,将该节点关闭,同时往右走,直到走到深度为H的树的底,最后一只猴子的所在编号。
// 注:这种规则对根节点同样适用)
//解题思路;开始就建立一颗深度为20的满二叉树,给每个节点标注(深度+1),给每个节点按规则标号,供后边所用。
//其中建树和标(深度+1)和标号是难点,当建立好以后模拟就行了 ^-^。
#include<stdio.h>
#include<malloc.h>
struct Node
{
int date,h;//h存放节点的度 + 1
bool judge;//判断该点是关闭还是打开,初始都是关闭
struct Node *lchild,*rchild;
} *L,*R;
int num,n;
void CreatBintree(struct Node *head)
{//递归建立满二叉树,每个节点的h存放该节点的(度+1)
if(head->h==20||(head->lchild&&head->rchild)) return;
if(!head->lchild)
{
num=head->h+1;
L=(struct Node *)malloc(sizeof(struct Node));
L->h=num; L->lchild=NULL; L->rchild=NULL;
head->lchild=L;
CreatBintree(L);
}
if(!head->rchild)
{
num=head->h+1;
R=(struct Node *)malloc(sizeof(struct Node));
R->h=num; R->lchild=NULL; R->rchild=NULL;
head->rchild=R;
CreatBintree(R);
}
}
void Ergodic(struct Node *head,int H)
{//对满二叉树进行初始化,也就是变为下面的形态
// 1
// 2 3
// 4 5 6 7
// ..........
if(head->h==H)
{
head->date=n;
n+=1;
}
if(head->h < H) Ergodic(head->lchild,H);
if(head->h < H) Ergodic(head->rchild,H);
}
void Close(struct Node *head,int H)
{//递归将所有的节点都设为关的状态
head->judge=false;
if(head->h < H) Close(head->lchild,H);
if(head->h < H) Close(head->rchild,H);
}
int main()
{
//-----建立深度为20的满二叉树-----//
struct Node *root;
root=(struct Node *)malloc(sizeof(struct Node));
root->h=1;
root->lchild=NULL;
root->rchild=NULL;
struct Node *head=root;
CreatBintree(head);
//--------------------------------//
int i,j;
//-----对满二叉树进行初始化(按规则标号)-----//
for(i=1,j=1;i<=20;i++,j*=2)
{
head=root;
n=j;
Ergodic(head,i);
}
//--------------------------------------------//
int H,N;
while(scanf("%d %d",&H,&N)&&!(H==0&&N==0))
{
head=root;
Close(head,H);//初始化为所有节点的都是关闭状态
while(N--)
{
head=root;
while(!(head->h==H))
{
if(!head->judge)
{//如果该点是关闭状态,将该点的状态变为打开,向左走
head->judge=true;
head=head->lchild;
}
else if(head->judge)
{//如果该点是打开状态,将该点的状态变为关闭,向右走
head->judge=false;
head=head->rchild;
}
}
}
printf("%d\n",head->date);
}
return 0;
}
这题居然还有可以直接模拟,这里讲的不错http://www.cnblogs.com/ljwTiey/p/4295704.html
没有想到,下边是代码。
#include<stdio.h>
int main()
{
int H,N,i,j;
while(scanf("%d %d",&H,&N)&&!(H==0&&N==0))
{
for(i=0,j=1;i<H-1;i++)
if(N%2)
{
j*=2;N=(N+1)/2;
}
else
{
j=2*j+1;N/=2;
}
printf("%d\n",j);
}
return 0;
}