关于《ACM/ICPC算法基础训练教程》这本书的一些解释与自我理解
1.3 递归算法
1.3.1 基本概念
递归是计算机科学的一个重要概念,递归的方法是程序设计中有效的方法,采用递归算法编写程序能使程序变得简洁和清晰。
一个函数直接或间接调用自己本身,这种函数称为递归函数。递归函数必须有一个结束条件。在竟赛中,递归的思想有着重要的应用。例如,一些树形的数据结构、搜索问题、树和图的很多算法,以及数学上递归定义的函数,等等。
直接递归:
void a(){
a();
//直接调用自身
间接递归:
void b(){
:
c();
:
}
void c(){
:
b();
:
}
1.3.2 例题讲解
【例1-6】 最小公倍数
题目描述:
给定两个正整数,计算这两个数的最小公倍数。输人包含多组测试数据,直到文件结束,每组一行,包括两个不大于1000的正整数。对于每组数据,计算出这两个数的最小公倍数,每组样例输出一行。
输入样例:
10 14
9 18
输出样例:
70
18
题目来源:
HDU 1108
http://acm.hdu.edu.cn/showproblem. php?pid=1108
题目解析:
首先根据欧几里得算法求得这两个数的最大公约数,进而求其最小公倍数欧几里得算法的描述如下:
gcd(a,b)=gcd(b,a mod b)(a>bHa mod b不为0)
参考代码:
#include<iostream>
using namespace std;
//利用欧几里得算法计算最大公约数
int gcd(int a,int b){
if(a<b)swap(a,b); //保证算法条件
if(abb==0)return b
return gcd(b, agb);
}
int main()
{
int a, b;
while(cin>>a>>b){
cout<<a* b/gcd(a,b)<<endl;
}
return 0;
}
【例1-7】 Password.
题目描述:
给出一棵二叉树的前序遍历和中序遍历,找出这棵二叉树的后序遍历,题目保证这棵二叉树各个结点的值不重复。
有多组输入样例,每组样例包含两行,第一行为二叉树的前序遍历,第二行为二叉树的中序遍历,每组样例输出一行表示该二叉树的后序遍历。
输入样例:
ABC
BAC
输出样例:
BCA
题目来源:
TO] 3988,TJU Team Selection 2013
http://acm.tju.edu.cn/toj/showp.php?pid=3988
题目解析:
需要实现的函数应当具备如下功能,它可以把一棵树的前序遍历和中序遍历转换成后序遍历。根据前序遍历的第一个字符可以确定这棵树的根,从中序遍历找到这个字符就可以把这棵树的左子树和右子树区分开来,从而递归调用这个函数解决每个子树。终止条件:当一棵树没有结点的时候,它是一棵空二叉树,直接返回;当一棵二叉树只有一个结点的时候,只有根,将这个值保存到后序遍历的结果中,然后返回.
参考代码:
#include<iostream>
#include<string>
using namespace std;
char ans[30];
int t;
void solve(string s1, string s2) {
if (s1.length() == 0) return; //空二叉树
if (s1.length() == 1) {
ans[t++] = s1[0];
return;
}
int tt = s2.find(s1[0]);
solve(s1.substr(1, tt), s2.substr(0, tt));//左子树的后序遍历
solve(s1.substr(tt + 1, s1.length() - tt - 1), s2.substr(tt + 1, s2.length() - tt - 1));//右子树的后序遍历
ans[t++] = s1[0];
}
int main() {
string stra, strb;
while (cin >> stra >> strb) {
int len = stra.length();
t = 0;
solve(stra, strb);
ans[len] = '\0';
cout << ans << endl;
}
return 0;
}