1.递推递归
2.DFS
3.BFS
1.递推递归
一开始学的时候没分清楚过,看到有视频是这么说的:
其实还是有点抽象......
好吧那么写写看就知道了
#include<bits/stdc++.h>
using namespace std;
int jiec_gui(int n){//原有问题变成新问题,新问题解决方法一样
if(n==1)
return 1;//1.边界 (终止条件)
else
return n*jiec_gui(n-1);//2.操作 (关系式)
}//递归(调用自己) 从边界开始看
int main(){
int n;
cin>>n;
cout<<jiec_gui(n)<<endl;//递推的阶乘
int a[n];
a[0]=1;
a[1]=2;
for(int i=n-1;i>1;i--){
a[i]=a[i-1]*n;
}//递推 时间复杂度更简单点
cout<<a[n-1];
return 0;
}
一般来讲(不知道是不是),递归要用函数,自己调用自己,递推则是数组,没有自己调用自己
但是两者都有很重要的东西:1.表达式 2.边界
递推要注意数组不要越界
关于时间复杂度,递推更小点,递归更大
因地制宜地用罢
2.DFS
有点要把人搞疯了......其实看看原理动图还是理解的,关键就是怎么写,不然原子弹原理上网一查就知道了,那为什么不是每个国家人手核武呢?
下面以全排列为例:
//全排列
#include<bits/stdc++.h>
using namespace std;
int box[100],n;//箱子 ,盒子数
bool book[100];//标记 :是否在box中
void dfs(int step){
if(step==n+1){//箱子里面装满了
for(int i=1;i<=n;i++){
printf("%d ",box[i]);
}
printf("\n");
return;//返回上级
}
for(int i=1;i<=n;i++){
if(book[i]==0){
box[step]=i;//i号牌放入第step个box中
book[i]=1;//i号牌进入box
dfs(step+1);//重复
book[i]=0;//拿出来i号牌
}
}
return;//返回上级
}
int main(){
cin>>n;
dfs(1);
return 0;
}
/*图示
①
| \
② ⑥
| \ \
③⑤⑦
|
④
*/
(好吧这个图示确实抽象)
咳咳,在这里,DFS还用到递归的思想,就是有一步自己调用自己
要注意的有:1.变量的设置,不要只设在main里面
2.注意这里的step,第一眼看上去蒙了,可以打个注释方便看
3.既然是有递归的思想,记得要设置边界
4.注意要设置一个book也就是记录是否使用了第i张牌
5.可以在纸上先模拟一遍(这不叫纸上谈兵)
有点难理解,可以多看看题
比如迷宫:
#include<bits/stdc++.h>
using namespace std;
int N,M,T;
int visit[10][10];//棋盘上有没有走过
int s_x,s_y;//起点位置
int t_x,t_y;//终点位置
int x2,y2;//更新位置
int nxt[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//行动 *
int s=0;//计数器
void dfs(int x,int y){//现在的位置
if(x==t_x&&y==t_y){
s++;
return;
}//到终点
for(int k=0;k<4;k++){
x2=x+nxt[k][0];//更新x
y2=y+nxt[k][1];//更新y
if(x2==0||x2>N||y2==0||y2>M||visit[x2][y2]!=0){
continue;//越界不执行
}
visit[x][y]=1;
dfs(x2,y2);
visit[x][y]=0;
}//*
return;
}
int main(){
cin>>N>>M>>T;
cin>>s_x>>s_y;
cin>>t_x>>t_y;
int zx,zy;
for(int i=0;i<T;i++){
cin>>zx>>zy;
visit[zx][zy]=-1;
}
//有障碍
visit[s_x][s_y]=1;//*起点始终被访问过
dfs(s_x,s_y);
cout<<s;
return 0;
}
注意和前面不一样了,要考虑越界的问题
还有上下左右移动的nxt很巧妙,可多加理解
注意边界
这个还好,但是八皇后实在是搞不明白
3.BFS
我看这个东西比DFS还要抽象一点......
理解没有DFS好,那么看看代码罢
以下面为例:
求最短需要几步
代码如下:
#include<iostream>
using namespace std;
struct node
{
int x,y; //坐标
int s; //步数
};
node que[2501];
int n, m;//大小
int p, q;//终点
int flag;
int head,tail;
//mmp数组表示地图
int mmp[51][51];
int visit[51][51];
//定义一个用于表示走的方向的数组
int nxt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
void BFS(int sx, int sy){
head=tail=1;
flag=0;
que[tail].x=sx;
que[tail].y=sy;
que[tail].s=0;
tail++;
visit[sx][sx]=1;
flag=0;
while(head<tail)
{
int tx,ty;
for(int i=0;i<3;i++)
{
tx=que[head].x+nxt[i][0];
ty=que[head].y+nxt[i][1];//更新
if(tx == p && ty== q){
flag=1;
break;
}//四方向搜索
if(tx<1||ty<1||tx>n||ty>m) continue;//是否越界
if(visit[tx][ty]!=1 && mmp[tx][ty]==0)//如果没障碍且没走过
{
que[tail].x=tx;//存入队列
que[tail].y=ty;
que[tail].s=que[head].s+1; //等于上一步+1
tail++;
visit[tx][ty]=1;//这格走过了
}
}
if(flag) {//找到了
cout<<que[head].s+1;//下一次就到目标点,步数还差一次
break;
}
head++;//没找到,把已经走过的(sx,sy)等等的点从队列里面拿掉
}
return;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>mmp[i][j];
int startx,starty;//起始点
cin>>startx>>starty>>p>>q;
BFS(startx, starty);
return 0;
}
(不知道自己打的注释对不对)
针对此题,可见,没有用到递归的思想,但是这里用结构体来模拟了一下队列
head和tail:head就是指向第一个的指针,tail则是最后一个的后面一个
看上去队列里面只能存在步数相同的?或许吧
还不是很理解,还需要自己下来写一遍