本文图片和部分材料来源网络,如有侵权,请联系我删除,谢谢!
递归
首先我们先要知道递归是什么:
递归,是在运行的过程中调用自己
然而,递归也可能导致性能问题,因为每次函数调用都会占用一定的内存空间,如果递归深度过大,可能会导致栈溢出错误(递归使用栈来完成的)。
但,递归也是要有条件的:
1.子问题须与本来的问题是做同样的事。
2.有递归边界(化简为非递归状况处理)。
常见的几种用递归解决的问题:
1.斐波那契数列的第X项
2.X的阶乘
3.汉诺塔
那么,作为初学者,我们先来学习最简单的:阶乘
(递归简介)
以下,是阶乘的递归过程图解
1.阶乘
我们不难发现,n在<=1的时候,返回的值是1,而其它情况则都是“n*fact(n-1);”
那我们可以得到递归部分是:
int f(int n)//这里我将函数名简写了一下,不影响实际作用
{
if(n<=1)
{
return 1;
}
else
{
return n*f(n-1);
}
}
最后我们再加上输入输出、基本框架就可以了
#include<bits/stdc++.h>
using namespace std;
int f(int n)
{
if(n<=1)
{
return 1;
}
else
{
return n*f(n-1);
}
}
int main()
{
int n;
cin>>n;
cout<<f(n);
return 0;
}
2.八皇后问题
那我们再看经典问题——八皇后问题和查找路线问题;
我们首先来看他的递归边界是什么;
我们知道,八皇后问题中如果我们摆放了八个棋子以上,我们就要退出(return)
那么摆放八个棋子以上就是我们的递归边界
我们知道,如果摆放八个棋子以上,那么这种方法成立,所以我们就要输出这种方法并且退出;
反之,就继续调用本身搜索
我们继续来思考,我们从几开始调用?
我们知道,我们首先要摆放第一个棋子,所以就从 dfs (1) 开始调用
而我们可以走一个点,标记一个点,这样就不会重复了。
可我们要输出多种方法,如果使用上述的算法,确实不会重复了,可也会少走许多路线导致WA
于是,我们就可以采用回溯的思想!
我们将这个点标记后搜索一遍,然后再取消标记。这样,我们就可以采用回溯的思想来修复BUG了
那么我们上代码:
#include<bits/stdc++.h>
using namespace std;
int cnt,n=8,a[15],b[105],c[105],d[105];
void dfs(int x)
{
if(x==9)
{
cnt++;
for(int i=1;i<=n;i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
return ;
}
for(int i=1;i<=n;i++)
{
if(b[i]==0&&c[i+x]==0&&d[i-x+7]==0)
{
b[i]=1;
c[i+x]=1;
d[i-x+7]=1;
a[x]=i;
dfs(x+1);
b[i]=0;
c[i+x]=0;
d[i-x+7]=0;
}
}
}
int main()
{
dfs(1);
cout<<cnt;
return 0;
}