今天上来就是一道通过二元数组建立二叉树然后DFS和BFS的题。
忘了不说。。。也有点复杂。。。
看来今天是刷不完递归了
递归第一题:
题目:
给出一个二叉树,输出它的最大宽度和高度。
输入描述:
第一行一个整数n。
下面n行每行有两个数,对于第i行的两个数,代表编号为i的节点所连接的两个左右儿子的编号。如果没有某个儿子为空,则为0。
输出描述:
输出共一行,输出二叉树的最大宽度和高度,用一个空格隔开。
样例输入:
5
2 3
4 5
0 0
0 0
0 0
样例输出:
2 3
数据范围及提示:
n<16
默认第一个是根节点
以输入的次序为编号
2-N+1行指的是这个节点的左孩子和右孩子
注意:第二题有极端数据!
1
0 0
这题你们别想投机取巧了,给我老老实实搜索!
我的答案:
。。。这道题的提示有点硬核啊。。。(笑哭)
得,那就按部就班DFS和BFS吧
大体思想是明白的,一个递归,一个出入队。
开始想写链表。。。无奈已经忘记了,太难写。
后来按照别人的,磕磕绊绊,定义了一个结构体,然后申请了一个数组出来。
一些语法要点要注意。
另外,从本题中要学会运用queue的。.empty()、.size()等函数。
这题掌握的不够扎实,知道个大概,细节却不会实现,这么经典的算法,一定要好好掌握。
今天状态不好,心不静,要注意调整。至少还得再做一题。
本题如下:
#include <iostream>
#include <queue>
using namespace std;
struct node //二叉树结构体
{
int lchild;
int rchild;
};
int dfs(node *arr,int n) //深度优先前序递归
{
int d=0;
if(n>0)
{
int ld=0,rd=0;
ld=dfs(arr,arr[n].lchild);
rd=dfs(arr,arr[n].rchild);
d=(ld>rd)?ld+1:rd+1;
}
return d;
}
int bfs(node *arr)
{
int w;
queue<node> t;
int i=0;
int temp=1;
t.push(arr[1]);
while(!t.empty())
{
int i=0;
temp=t.size();
while(i<temp)
{
if(t.front().lchild!=0) t.push(arr[t.front().lchild]);
if(t.front().rchild!=0) t.push(arr[t.front().rchild]);
t.pop();
i++;
}
if(temp>w) w=temp;
}
return w;
}
int main()
{
int n=0,i=0,d=0,w=0;
cin>>n;
node *arr=new node[n+1];
for(i=1;i<=n;i++)
{
cin>>arr[i].lchild>>arr[i].rchild;
}
w=bfs(arr);
d=dfs(arr,1);
cout<<w<<" "<<d<<endl;
return 0;
}
递归第二题:
题目:
同学们在做题时常遇到这种函数
f(x)=5 (x>=0)
f(x)=f(x+1)+f(x+2)+1 (x<0)
下面就以这个函数为题做一个递归程序吧
输入描述:
一个数表示f(x)中x值
大家注意就一个数,前面代表样例编号
输出描述:
一个数表示值
大家注意就一个数,前面代表样例编号
样例输入:
样例一:0
样例二:-5
样例输出:
样例一:5
样例二:77
数据范围及提示:
x>=-30
我的答案:
恕我直言,这道题真的好简单。。。不像是做题,像是做外文翻译。
属于打一巴掌之后的甜枣。
这也告诉我不能总是急吼吼的。当下的题难,也许以后的题简单。
平心静气,不要总是着急。。。
要平静,要冷静,要留得青山在,要泰山崩于前而色不变。
代码:
#include<iostream>
using namespace std;
int f(int x)
{
int r=0;
if(x>=0) r= 5;
else r=f(x+1)+f(x+2)+1;
return r;
}
int main()
{
int n=0,result=0;
cin>>n;
result=f(n);
cout<<result;
return 0;
}
加油哇!
果然下午手痒,又来刷题了~
递归第三题:
题目:
3n+1问题是一个简单有趣而又没有解决的数学问题。这个问题是由L. Collatz在1937年提出的。克拉兹问题(Collatz problem)也被叫做hailstone问题、3n+1问题、Hasse算法问题、Kakutani算法问题、Thwaites猜想或者Ulam问题。
问题如下:
(1)输入一个正整数n;
(2)如果n=1则结束;
(3)如果n是奇数,则n变为3n+1,否则n变为n/2;
(4)转入第(2)步。
克拉兹问题的特殊之处在于:尽管很容易将这个问题讲清楚,但直到今天仍不能保证这个问题的算法对所有可能的输入都有效——即至今没有人证明对所有的正整数该过程都终止。
输入描述:
第一行是一个整数T.表示输入数据的组数.
第二行是T个正整数n.
输出描述:
对于每个正整数n,每行输出一个数s,表示n通过多少步变换会变成1,如果n无法变成1,则输出-1.
样例输入:
3
1 2 3
样例输出:
0
1
7
数据范围及提示:
1 <= T <= 100
1 <= n <= 10000
我的答案:
今天下午的状态还好哈。
这道题有一个疑问,就是怎么表达-1这种状况呢
如何判断能不能变成1呢。Kevin说可以设置全局变量,统计一下递归次数,太多了就返回。
比如程序要求1s中完成,根据计算如果递归超过10000次就超时了,那么就设置5000次。
可是我这题没写超时的处理,也成功了,那就是进入递归以后一层一层耗着吧。。。估计测试用例里没有失败的情况。
另外,查了一下,这个问题会有溢出的风险。不过题目给出的范围并不大,所以可能是白银级别的原因吧,没在这个地方设置障碍。
我看到有人用的while循环,不过这是一道递归类的题目嘛,就写递归吧:
#include <iostream>
using namespace std;
int n[100];
int collatz(int n)
{
int t=0;
if(n!=1){
if(n%2==1) t=1+collatz(3*n+1);
else t=1+collatz(n/2);
}
return t;
}
int main()
{
int t=0,i=0,temp=0;
cin>>t;
for(i=0;i<t;i++)
{
cin>>n[i];
}
for(i=0;i<t;i++)
{
temp=collatz(n[i]);
cout<<temp<<endl;
}
return 0;
}
递归第四题:
题目:
求一棵二叉树的前序遍历,中序遍历和后序遍历
输入描述:
第一行一个整数n,表示这棵树的节点个数。
接下来n行每行2个整数L和R。第i行的两个整数Li和Ri代表编号为i的节点的左儿子编号和右儿子编号。
输出描述:
输出一共三行,分别为前序遍历,中序遍历和后序遍历。编号之间用空格隔开。
样例输入:
5
2 3
4 5
0 0
0 0
0 0
样例输出:
1 2 4 5 3
4 2 5 1 3
4 5 2 3 1
数据范围及提示:
n <= 16
我的答案:
这题很常规,疯狂递归,也正好复习了第一题不熟悉的结构体和树的基本操作。
但是同学,看题啊,要看题目啊同学!!不看输入描述和输出描述的嘛???数字之间有空格哒傻蛋!!!
代码如下:
#include <iostream>
using namespace std;
struct node
{
int lc;
int rc;
};
void preorder(node *arr,int n)
{
if(n!=0)
{
cout<<n<<" ";
preorder(arr,arr[n].lc);
preorder(arr,arr[n].rc);
}
}
void inorder(node *arr,int n)
{
if(n!=0)
{
inorder(arr,arr[n].lc);
cout<<n<<" ";
inorder(arr,arr[n].rc);
}
}
void posorder(node *arr,int n)
{
if(n!=0)
{
posorder(arr,arr[n].lc);
posorder(arr,arr[n].rc);
cout<<n<<" ";
}
}
int main()
{
int n=0,i=0;
cin>>n;
node *arr=new node[n+1];
for(i=1;i<=n;i++)
{
cin>>arr[i].lc>>arr[i].rc;
}
preorder(arr,1);
cout<<endl;
inorder(arr,1);
cout<<endl;
posorder(arr,1);
return 0;
}
递归第五题:
题目:
汉诺塔问题(又称为河内塔问题),是一个大家熟知的问题。在A,B,C三根柱子上,有n个不同大小的圆盘(假设半径分别为1-n吧),一开始他们都叠在我A上(如图所示),你的目标是在最少的合法移动步数内将所有盘子从A塔移动到C塔。
游戏中的每一步规则如下:
1. 每一步只允许移动一个盘子(从一根柱子最上方到另一个柱子的最上方)
2. 移动的过程中,你必须保证大的盘子不能在小的盘子上方(小的可以放在大的上面,最大盘子下面不能有任何其他大小的盘子)
如对于n=3的情况,一个合法的移动序列式:
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
给出一个数n,求出最少步数的移动序列
输入描述:
一个整数n
输出描述:
第一行一个整数k,代表是最少的移动步数。
接下来k行,每行一句话,N from X to Y,表示把N号盘从X柱移动到Y柱。X,Y属于{A,B,C}
样例输入:
3
样例输出:
7
1 from A to C
2 from A to B
1 from C to B
3 from A to C
1 from B to A
2 from B to C
1 from A to C
数据范围及提示:
n<=10
我的答案:
经典的汉诺塔问题。递归中的经典问题。甚至可以不管逻辑,只面向实际情形。
今天才知道汉诺塔的背景故事:
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面。僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。
为了这个先输出次数再输出过程,我简单粗暴地用了两次递归。
测试通过了,也不想再想了。
好像有点感冒。
代码:
#include <iostream>
using namespace std;
int hanoitime(int n,char a2,char b2,char c2)
{
int t=0,t1=0,t2=0;
if(n==1) t=1;
else
{
t1=hanoitime(n-1,a2,c2,b2);
t2=hanoitime(n-1,b2,a2,c2);
t=t1+t2+1;
}
return t;
}
void hanoiout(int n,char a2,char b2,char c2)
{
if(n==1) cout<<n<<" from "<<a2<<" to "<<c2<<endl;
else
{
hanoiout(n-1,a2,c2,b2);
cout<<n<<" from "<<a2<<" to "<<c2<<endl;
hanoiout(n-1,b2,a2,c2);
}
}
int main()
{
int n=0,t=0;
cin>>n;
t=hanoitime(n,'A','B','C');
cout<<t<<endl;
hanoiout(n,'A','B','C');
return 0;
}
喜升白银!解锁黄金!撒花✿✿ヽ(°▽°)ノ✿
喜悦转瞬即逝,随之而来的是更多更难的题目。
突然觉得人生也是这样吧。成功的快意很快就消散了,随之而来的是更多更艰巨的挑战。
快乐是短暂的,艰难和困苦却是长久的么?
不要这样想呀。
问题的原因不在生活,而在自己。
若是把迎接挑战的过程当成幸福,而成功这一事件不值一提,那么喜悦也是长久的了~
接受黄金段位的挑战吧!我一定要拿下黄金!