NYOJ 题目63 小猴子下落(满二叉树的建立与遍历)



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;
}
	






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值