LQ训练营(C++)学习笔记_广度优先搜索

四、广度优先搜索

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需要借助队列来实现:

  1. 初始的时候把起始点放到队列中,并标记起点访问。
  2. 如果队列不为空,从队列中取出一个元素x,否则算法结束。
  3. 访问和x相连的所有点v,如果v没有被访问,把v入队,并标记已经访问。
  4. 重复执行步骤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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值