这里写目录标题
四、广度优先搜索
1、队列的概念
队列是一种线性的数据结构,和栈一样是一种运算受限制的线性表。只允许从表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
C++中queue
的实现在一个<queue>
头文件中,在代码开头引入这个头文件,并在引入所有头文件后加上一句using namespace std
#include<queue>
using namespace std;
int main(){
return 0;
}
C++中直接构造一个queue的语句为:queue<T>q
。这样定义一个名为q的存储T类型数据的队列。
2、小朋友报数问题
2.1 问题描述
借助队列完成报数游戏的计算,假设有 n个小朋友,报到m的小朋友退出游戏。有n个小朋友做游戏,他们的编号分别是1,2,3…n。他们按照编号从小到大依次顺时针围成一个圆圈,第一个小朋友从1开始报数,依次按照顺时针方向报数(报数的值加一),每个报m的人会离开队伍,然后下一个小朋友会继续从1开始报数,直到只剩下一个小朋友为止。
求最后一位小朋友的编号。
2.2 代码实现
#include<iostream>
#include<queue>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
queue<int>q;//定义一个int类型的队列q
for(int i=1;i<=n;i++){
q.push(i);
}
int cur=1;
while(q.size()>1){
int x=q.front();//从队首取出一个小朋友
q.pop;
if(cur==m){//如果报数是m就退出游戏
cur=1;
}else{//如果不是m,则重新入队
q.push(x);
cur++;
}
}
cout<<q.front()<<endl;//输出剩下小朋友的编号
return 0;
}
3、广度优先搜索概念
广度优先搜索,又称宽度优先搜索,简称bfs,先将与起始点距离较近的点搜索完毕,再继续搜索较远的点,一层层的扩展。
bfs需要借助队列来实现:
- 初始的时候把起始点放到队列中,并标记起点访问。
- 如果队列不为空,从队列中取出一个元素x,否则算法结束。
- 访问和x相连的所有点v,如果v没有被访问,把v入队,并标记已经访问。
- 重复执行步骤2 。
4、走迷宫问题
4.1 问题描述
迷宫是许多小方格构成的矩形,在每个小方格中有的是墙(用1表示),有的是路(用0表示)。走迷宫就是从一个小方格沿上、下、左、右四个方向到邻近的方格,当然不能穿墙。
实现生成迷宫(从文本中读取数据生成),输出迷宫(图案方式),探索迷宫路径(最短路径),输出迷宫路径(图案方式)。
4.2 代码实现
#include <iostream>
#include <string>
#include <queue>
using namespace std;
int n, m;
string maze[110];
bool vis[110][110];
int dir[4][2] = {{‐1, 0}, {0, ‐1}, {1, 0}, {0, 1}};
bool in(int x, int y) {
return 0 <= x && x < n && 0 <= y && y < m;
}
struct node{
int x,y,d;
node(int xx,int yay,int dd){//定义结构体,记录坐标x,y以及当前使用的步数d
x=xx;
y=yy;
d=dd;
}
};
int bfs(int sx,int sy){
queue<node>q;
q.push(node(sx,sy,0));
vis[sx][sy]=true;
while(!q.empty()){//队列中有元素时,取出队首元素
node now=q.front();
q.pop();
for(int i=0;i<4;i++){//从队列中取出点去扩展其他的点
int tx=now.x+dir[i][0];
int ty=now.y+dir[i][1];
if(int(tx,ty)&&maze[tx][ty]!=‘*’&&!vis[tx][ty]){//(tx,ty)合法且没有被访问
if(maze[tx][ty]==‘T’){//如果是终点,直接返回
return now.d+1;
}else{//不是终点,把这个点标记访问并压入栈中
vis[tx][ty]=true;
q.push(node(tx,ty,now.d+1));
}
}
}
}
return -1;//没有访问到终点,返回-1,表示没有找到起点到终点的路径
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> maze[i];
}
int x, y;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (maze[i][j] == 'S') {
x = i, y = j;
}
}
}
cout<<bfs(x,y)<<endl;
return 0;
}
5、过河卒问题
5.1 问题描述
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m)(n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。
5.2 代码实现
#include<iostream>
using namespace std;
int dir[8][2]={{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,-1}};
bool d[30][30];//用于标记马的控制点,该位置卒不能通过
int main(){
int n,m,cx,cy;//n,m是棋盘的大小,cx,cy是马的位置
cin>>n>>m>>cx>>cy;
d[cx][cy]=true;
for(int i=0;i<8;i++){
int tx=cx+dir[i][0];
int ty=cy+dir[i][1];
if(tx>=0&&tx<=n&&ty>=0&&ty<=m){
d[tx][ty]=true;
}
}
dp[0][0]=1;//能走到位置(i,j)的方案数量,先初始化然后进行递推
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
if(d[i][j]==false){//递推公式dp[i][j]=dp[i-1][j]+dp[i][j-1],为防止数组越界,把i和j分开处理。
if(i){
dp[i][j]+=dp[i-1][j];
}
if(j){
dp[i][j]+=dp[i][j-1];
}
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}