递归的作用:
1、代替多重循环 ,循环层数不明的问题。(n皇后)
2、本身是递归定义的问题。(逆波兰表达式)
3、将问题分解成多个规模更小子问题进行求解。(斐波那契数列)
个人感觉在第3个作用的思想是算法竞赛中最常用的。
找到合适的办法缩小问题规模,然后找到递推关系,确定好终止条件。
这里要特别贴上n皇后问题的代码实现:
#include<iostream>
#include<math.h>
using namespace std;
void Nqueen(int k); //以行数来进行递归
int QueenPos[100];
int n;
int ans=0;
int main()
{
cin>>n;
Nqueen(1);
cout<<ans;
return 0;
}
void Nqueen(int k)
{
if(k>n) {
for(int i=1;i<n;i++)
{
cout<<QueenPos[i]<<" ";
}
cout<<QueenPos[n]<<endl;
ans++;
}
else {
for(int i=1;i<=n;i++) //该行每一个位置试一下
{
int j;
for(j=1;j<k;j++)
{
if(QueenPos[j]==i||abs(QueenPos[j]-i)==k-j) break;
}
if(j==k) //该位置合适
{
QueenPos[k]=i;
Nqueen(k+1);
}
}
}
}
之前有自己写过n皇后的问题,当时是另引入一个二维数组记录棋盘中不可走的位置(没放入一个皇后确定一部分不可走的位置) 这种思路是完全不适用于递归的!!!!!
代码实现中相当于尝试了所有的情况,其中有特别关键的不好理解一环就是 当在求解k行是没有位置满足这个时候递归函数返回到上一行的Nqueen(k+1),相当与此句结束,执行i++,也就是说当当前行所有位置都不可行的时候会回到上一行去改变上一行的放的位置。
按照我之前的思路这样的回溯,是没有办法实现的,除非在这个时候再去把之前设置的不可走位置改掉然后重新搞,这样过于繁琐。因此每走一步判断皇后是否与已走皇后冲突是更加优秀的方案。
这里特别强调一下对角线判断的方法 行号差==列号差 即对角线
这里贴上看起来相当简洁的逆波兰表达式求解:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
double exp()
{
char s[20];
cin>>s;
switch(s[0])
{
case '+': return exp()+exp();
case '-': return exp()-exp();
case '*': return exp()*exp();
case '/' : return exp()/exp();
default: return atof(s);
}
}
int main()
{
printf("%lf",exp());
return 0;
}
逆波兰表达式 =符号 逆波兰表达式 逆波兰表达式
终止条件:逆波兰表达式=数字
cin的输入在" "处结束,scanf也是如此
之前看到很多字符串处理的题目,就各种不想做,其实题目给出的输入以空格分开已经是提供了便利。
atof就是把"double" 变成 double(有那么一点点类似python里面的eval)