NYOJ-63 小猴子下落(二叉树及优化算法详解)
小猴子下落
- 描述
-
有一颗二叉树,最大深度为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
第一感觉就是这题题目思路和清晰,一开始想到直接算出答案输出即可,考虑到正在学习数据结构,因此还是选择了用树进行暴力求解。
没想到运气好居然过了。供学习树的朋友一同学习。
下面还将讲解优化算法:
树写代码如下:
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
struct node
{
int data;
int flag;
node *lchild,*rchild;
node();
};
node::node()
{
flag=-;
rchild=lchild=NULL;
}
void createTree(int d,node *&root)
{
queue<node *> q;
while(!q.empty())
q.pop();
root=new node;
static int count=;
root->data=++count;
q.push(root);
node *t=root;
while(count!=pow(,d)-)
{
t=q.front();
q.pop();
t->lchild=new node;
t->lchild->data=++count;
q.push(t->lchild);
t->rchild=new node;
t->rchild->data=++count;
q.push(t->rchild);
}
t=NULL;
count=;
}
/*
void LevelOrder(node *root)
{ //队列实现
queue<node *> q;
node *t=root;
if(t!=NULL) q.push(t); //根非空,入队
while(!q.empty()) //队不空
{
t=q.front();
q.pop(); //出队
cout<<t->data<<" ";
if(t->lchild)
q.push(t->lchild); //遍历左孩子
if(t->rchild)
q.push(t->rchild); //遍历右孩子
} }
*/
void Go(int &t,node *&root)
{
if(root->lchild&&root->rchild){
if(root->flag==-)
{
Go(t,root->lchild);
root->flag=;
}
else
{
Go(t,root->rchild);
root->flag=-;
}
}
else
t=root->data;
} int main()
{
int d,num;
while(cin>>d>>num,d&&num){
node *root=NULL;
createTree(d,root);
int t;
for(int i=;i<num;i++)
Go(t,root);
cout<<t<<endl;
}
return ;
}
tree
但是如果测试数据有N组,层数D有19层呢(D<=20),那么树将建立2^19-1个结点,时间和空间耗费都很大。那么怎么办?
下面讲一下优化算法:
1 | ||||||||||||||
2 | 3 | |||||||||||||
4 | 5 | 6 | 7 | |||||||||||
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
根据右图测试数据可知,一共有n行(3,4,5),x个猴子中每2^n出现一循环,理由就是它是满二叉树。
根据左图四层我们列出数据看看:
第1只猴子 | 1 | 2 | 4 | 8 |
第2只猴子 | 1 | 3 | 6 | 12 |
第3只猴子 | 1 | 2 | 5 | 10 |
第4只猴子 | 1 | 3 | 7 | 14 |
第5只猴子 | 1 | 2 | 4 | 9 |
第6只猴子 | 1 | 3 | 6 | 13 |
第7只猴子 | 1 | 2 | 5 | 11 |
第8只猴子 | 1 | 3 | 7 | 15 |
请读者看看四层二叉树(上左图)和上表中对比不难发现,进入第n个结点的次数i为奇数(即前面已有n-1过猴子访问过该结点),那么遍历其左子树根;
若为偶数,则遍历其右子树根。
因此,对照上表,得出规律:i为奇数,k=k*2;i=(i+1)/2;//第i个进入左子树
i为偶数,k=k*2+1;i=i/2; //第i个进入右子树
例如
第1个猴子:则对于第一个结点来说,i=1为奇数,那么下一个要走的结点k=1*2=2;然后i=(1+1)/2=1(第一个进入左子树),继续判断其左子树i的奇偶性……
第3个猴子:则对于第一个结点来说,i=3为奇数,那么下一个要走的结点k=1*2=2;然后i=(3+1)/2=2(第二个进入左子树)……
第5个猴子:则对于第一个结点来说,i=5为奇数,那么下一个要走的结点k=1*2=2;然后i=(5+1)/2=3(第三个进入左子树)……
……
1 for (int j=0;j<d-1;j++)
2 if(i%2) {k=k*2;i=(i+1)/2;}
3 else {k=k*2+1;i /=2;}
OK接着按照输入标准写出完整算法如下:
1
2 #include<iostream>
3 using namespace std;
4
5 int main()
6 {
7 int d,i,k;
8 while(cin>>d>>i && (d+i) !=0)
9 {
10 k=1;
11 for (int j=0;j<d-1;j++)
12 if(i%2) {k=k*2;i=(i+1)/2;}
13 else {k=k*2+1;i /=2;}
14 cout<<k<<endl;
15
16 }
17 }
当然,你可以将/2换成位运算左移一位,效率更高。
NYOJ-63 小猴子下落(二叉树及优化算法详解)的更多相关文章
- nyoj 63 小猴子下落 思维
nyoj 63 小猴子下落 题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=63 思路: 不需要用指针创建二叉树,也不需要用数组来模拟二叉 ...
- nyoj 63 小猴子下落
小猴子下落 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 有一颗二叉树,最大深度为D,且所有叶子的深度都相同.所有结点从左到右从上到下的编号为1,2,3,····· ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- 安全体系(二)——RSA算法详解
本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...
- 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?
简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...
- 安全体系(一)—— DES算法详解
本文主要介绍了DES算法的步骤,包括IP置换.密钥置换.E扩展置换.S盒代替.P盒置换和末置换. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(二)——RSA算 ...
- 八大排序算法详解(动图演示 思路分析 实例代码java 复杂度分析 适用场景)
一.分类 1.内部排序和外部排序 内部排序:待排序记录存放在计算机随机存储器中(说简单点,就是内存)进行的排序过程. 外部排序:待排序记录的数量很大,以致于内存不能一次容纳全部记录,所以在排序过程中需 ...
- 第三十一节,目标检测算法之 Faster R-CNN算法详解
Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...
- [Network Architecture]DPN(Dual Path Network)算法详解(转)
https://blog.csdn.net/u014380165/article/details/75676216 论文:Dual Path Networks 论文链接:https://arxiv.o ...
随机推荐
- 自己编写的 C++ 超轻量级日志类
[自己编写的 C++ 超轻量级日志类(兼容vc++6.0.vs2010.vs2015)] 先来看效果: [测试文件:test.cpp] /* 作者:闫文山 时间:2017/07/02 介绍: 本日志类 ...
- localStorage与location的用法
1.localStorage 是h5提供的客户端存储数据的新方法: 之前,这些都是由 cookie 完成的.但是 cookie 不适合大量数据的存储,因为它们由每个对服务器的请求来传递,这使得 coo ...
- web项目直接在浏览器上访问不需要带.jsp,直接ip地址加项目名 在web.xml里配置
web.xml最上方 <welcome-file-list> <welcome-file> /view/login.jsp </welcome-file> < ...
- 百度BAE环境搭建
一.申请 1.http://bce.baidu.com/index.html 2.购买应用引擎BAE需要实名认证:http://console.bce.baidu.com/qualify/#/qual ...
- poj3276
Face The Right Way Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5121 Accepted: 237 ...
- EntityManager 实例化方法
Configure the EntityManager via a persistence.xml file <persistence xmlns="http://java.sun.c ...
- HDU 1864 最大报销额(DP)
题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1864 题目: 最大报销额 Time Limit: 1000/1000 MS (Java/Others) ...
- Oracle之plsql快速入门
打开系统输出 set serveroutput on; 只需要打开一次**书写格式 以斜杠/号 结束(基本结构) --declare --语句后面必须以;号结束 declare --用来区分变量名和表 ...
- 【学习笔记】C# 构造和析构
构造方法 构造方法是一个特殊的方法,负责初始化对象 构造方法名必须和类名一致 构造方法没有返回值,但可以有参数,能够重载 构造方法可以不写,系统会自动为类添加一个无参的默认构造 如果将构造方法设置为P ...
- C/C++中static关键字的用法
1.什么是static? static 是C/C++中很常用的修饰符,它被用来控制变量的存储方式和可见性. 1.1static的引入 我们知道在函数内部定义的变量,当程序执行到它的定义处时,编译器为它 ...