Week2 作业A 迷宫 bfs

  • 题意:

输入5*5矩阵,1表示墙,0表示可走。找出从左上角到右下角的最短路径所经过的坐标(输入保证有唯一解)

  • 做法:

bool型二维数组vis保存输入的01矩阵,1表示墙,0表示可走。map from保存每一个经过的坐标的前驱结点坐标。queue q保存每一层扩展时的中心结点。为方便层层扩展时遍历上下左右四个方向,定义数组dx[]={0,0,-1,1},dy[]={1,-1,0,0}。

初始化:将起点加入队列

当队列非空即还有待扩展的中心结点时(while循环):

取点:取出队首结点

特判终点:判断当前中心结点是否为终点,若是,输出方案(==>后面补充print(Point))

扩展结点:对上、下、左、右相邻的结点,判断合法性(1.不出边界 2.不是墙 !vis[x][y] 3.没到过 from.find(t)==from.end()),若合法,入队列,将(合法的相邻结点,中心结点)这一映射加入from。

输出方案print(Point):输出以结点p为终点的最短路径,因为从p到起点是逆序的,可采用两种方法:①递归输出:若当前结点是起点,输出该点;若当前结点不是起点,将其前驱结点到起点的路径输出,再输出当前结点 ②用vector将p到起点所经过的坐标存起来,然后将vector倒序输出  

  • 注意:

1.行列编号从0开始

2.输出的特殊格式,每行中间有无空格,每行之间有无空行,结尾有无空行。

3.(0,0)是起点,最初加入时没有前驱结点。在判断合法性时,当使用条件from.find(t)==from.end()判断是否到达过时,会把(0,0)判断为没有到达过,这样就会给(0,0)制造一个前驱结点。因此,在输出方案时,递归判断是否为起点,使用  “当前结点是否为(0,0)”  而不是  “from.find(t)==from.end()"

  • 总结:

对于要求输出方案的bfs,需要使用map保存路径,这样,vis只需要承担保存墙的功能,可以用一个bool型二维数组。如果需要计数步数,可以在输出路径的过程中计数,也可以把vis改为int型数组,在寻找路径的过程计数。

代码:

#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
struct Point{
	int a;
	int b;
	Point(int _a,int _b):a(_a),b(_b){}
	Point(){}
	//比较
	bool operator<(const Point &p)const{
		return a!=p.a ? a<p.a : b<p.b;
	}
};
const int maxn=10;
bool vis[maxn][maxn];//1代表墙
map<Point,Point> from;
queue<Point> q;
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};
int m=5,n=5;//行数列数 
void print(Point &p){
//	if(from.find(p)!=from.end()){ 无法终止 
	if(!(p.a==0&&p.b==0)){
		print(from[p]);
		printf(p.a==4&&p.b==4 ? "(%d, %d)":"(%d, %d)\n",p.a,p.b);
	}else{
		printf("(%d, %d)\n",p.a,p.b);
	}
}
void bfs(int sx,int sy,int tx,int ty)
{
	//初始化 
	Point p(sx,sy);
	Point t; 
	q.push(p);
	while(!q.empty()){
		//取出队首 
		p=q.front(); q.pop();
		//特判终点 
		if(p.a==tx&&p.b==ty){
			print(p);
			break;
		}
		//扩展结点
		for(int i=0;i<4;i++){
			int x=p.a+dx[i],y=p.b+dy[i];
			t=Point(x,y);
			//判合法 加队列
			//1.不出边界 2.不是墙 3.没走过 
			if(x>=0&&x<m&&y>=0&&y<=n&&!vis[x][y]&&from.find(t)==from.end()){
				q.push(t);
				from[t]=p;	
			} 
		} 
	}
}
int main()
{
	for(int i=0;i<5;i++)
	{
		for(int j=0;j<5;j++){
			cin>>vis[i][j]; 
		}
	}
	bfs(0,0,4,4);  
	return 0;
} 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值