既然讲课做了笔记,那么干脆把笔记上传一下啦!
1.DFS和BFS之间的区别、联系:
(1)深搜和宽搜都可以对我们的整个空间进行遍历、搜索
数据结构 使用空间
DFS 栈 O(h)
BFS 队列 O(2^h) 最短路
2.深度优先搜索(DFS)
例题:
1.排列数字(简单)
题目:
给定一个整数 n,将数字 1∼n排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
输入格式
共一行,包含一个整数 n。
输出格式
按字典序输出所有排列方案,每个方案占一行。
数据范围
1≤n≤7
输入样例:
3
输出样例:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
AC代码:
`#include<iostream>`
`#include<cstdio>`
`using namespace std;`
`const int N=10;`
`int n;`
`int path[N];//用一个全局数组来存一下状态,路径保存`
`bool st[N];//判断哪些数组用过了`
`void dfs(int u)`
`{`
`if(u==n)//当走到第n个的位置时`
`{`
`for(int i=0;i<n;i++)`
`{`
`printf("%d ",path[i]);`
`}`
`puts("");//每一个方案后面都要输出一个空行`
`return ;`
`}`
`for(int i=1;i<=n;i++)//当u<n时,说明还没有填完,则需要枚举一下当前这个位置可以填哪些数`
`{`
`if(!st[i])//找一个没有被用过的数`
`{`
`path[u]=i;`
`st[i]=true;//记录一下i已经被用过了`
`dfs(u+1);//递归下一层`
`st[i]=false;//恢复现场`
`}`
`}`
`}`
`int main()`
`{`
`cin>>n;//读入一个n`
`dfs(0);//从第0的位置开始看`
` return 0;`
`}`
2. n - 皇后问题(中等)
题目:
n−皇后问题是指将 n 个皇后放在 n×n的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n。
输出格式
每个解决方案占 n行,每行输出一个长度为 n的字符串,用来表示完整的棋盘状态。
其中 .
表示某一个位置的方格状态为空,Q
表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
AC代码:
***第一种搜索顺序:***
`#include<iostream>`
`#include<cstdio>`
`using namespace std;`
`const int N=20;`
`int n;`
`char g[N][N];`
`bool col[N],dg[N],udg[N];`
`void dfs(int u)`
`{`
`if(u==n)//说明已经找到一组方案`
`{`
`for(int i=0;i<n;i++)`
`{`
`puts(g[i]);`
`}`
`puts("");//每一个方案后面都要输出一个空行`
`return ;`
`}`
`for(int i=0;i<n;i++)`
`{`
`if(!col[i]&&!dg[u+i]&&!udg[n-u+i])`
`{`
`g[u][i]='Q';`
`col[i]=dg[u+i]=udg[n-u+i]=true;`
`dfs(u+1);//递归下一层`
`col[i]=dg[u+i]=udg[n-u+i]=false;//恢复现场`
`g[u][i]='.';`
`}`
`}`
`}`
`int main()`
`{`
`cin>>n;//读入一个n`
`for(int i=0;i<n;i++)`
`{`
`for(int j=0;j<n;j++)`
`{`
`g[i][j]='.';`
`}`
`}`
`dfs(0);//从第0的位置开始看`
`return 0;`
`}`
***第二种搜索顺序(更加原始):***
`#include<iostream>`
`#include<cstdio>`
`using namespace std;`
`const int N=20;`
`int n;`
`char g[N][N];`
`bool row[N],col[N],dg[N],udg[N];`
`void dfs(int x,int y,int s)`
`{//首先当前皇后的顺序一定不会超过n`
`if(y==n)
{
y=0,x++;
}
if(x==n)//说明我们已经枚举完最后一行了,就要停止了`
`{`
`if(s==n)//如果此时我们摆的皇后的次数等于n了,说明我们找到了一组解`
`{`
`for(int i=0;i<n;i++)//输出这组解`
`{`
`puts(g[i]);`
`}`
`puts("");`
`}`
`return ;`
`}`
`//枚举一下当前格子的两种选择`
`//第一种选择是不放皇后`
`dfs(x,y+1,s);//直接递归到下一个格子就可以了`
`// 第二种选择放皇后(这就需要判断一下)`
`if(!row[x]&&!col[y]&&!dg[x+y]&&!udg[x-y+n]) //首先这一行不能有皇后,其次,这一列不能有皇后,并且对角线上不能有皇后,并且反对角线上也不能有皇后`
`{`
`g[x][y]='Q';`
`row[x]=col[y]=dg[x+y]=udg[x-y+n]=true;//都放上了皇后`
`dfs(x,y+1,s+1);//然后递归到下一层`
`row[x]=col[y]=dg[x+y]=udg[x-y+n]=false;//恢复现场`
`g[x][y]='.';`
`}`
`}`
`int main()`
`{`
`cin>>n;//读入一个n`
`for(int i=0;i<n;i++)`
`{`
`for(int j=0;j<n;j++)`
`{`
`g[i][j]='.';`
`}`
`}`
`dfs(0,0,0);//从左上角开始搜,记录一下当前有多少个皇后`
`return 0;`
`}`
3.宽度优先搜索(BFS)
基本框架:
queue ← 初始状态
while queue不空
{
t ← 队头
拓展 t
}
例题:
1.走迷宫(简单)
题目:
给定一个 n×m的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角 (1,1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角 (n,m)处,至少需要移动多少次。
数据保证 (1,1)处和 (n,m)处的数字为 0,且一定至少存在一条通路。
输入格式
第一行包含两个整数 n 和 m。
接下来 n行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。
输出格式
输出一个整数,表示从左上角移动至右下角的最少移动次数。
数据范围
1≤n,m≤100
输入样例:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
输出样例:
8
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=110;
int n,m;
int g[N][N];//存地图`
int d[N][N];//存每一个点到起点的距离`
PII q[N*N];
int bfs()
{
int hh=0,tt=0;
q[0]={0,0};
memset(d,-1,sizeof d);//首先把所有距离初始化为-1,表示我们没有走过
d[0][0]=0;//表示已经走过了
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
while(hh<=tt)//while队列不空
{
pair<int,int> t=q[hh++];//每一次取出来对头元素
for(int i=0;i<4;i++)//每一次枚举一下4个方向
{
int x=t.first+dx[i],y=t.second+dy[i];//x表示沿着这个方向走会走到哪个点
if(x >= 0&& x <n &&y >= 0 && y < m && g[x][y]==0&&d[x][y]==-1)//如果沿着这个方向走的话,它在边界内并且这个点等于0是可以走的 并且还没有走过的话,就把它扩展出来
{
d[x][y]=d[t.first][t.second]+1;
q[++tt]={x,y};//把刚才的那个点加进去
}
}
}
return d[n-1][m-1];//然后把右下角的点的距离输出
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)//先读入整个地图
{
for(int j=0;j<m;j++)
{
cin>>g[i][j];
}
}
cout<<bfs()<<endl;//直接输出bfs
return 0;
}