优先队列版bfs maze

链接:登录—专业IT笔试面试备考平台_牛客网
题目描述:

输入:
5 5 1

..S..

.....

.###.

.....

..T..

1 2 3 3

5 5 1

..S..

.....

.###.

.....

..T..

3 3 1 2

5 5 1

S.#..

..#..

###..

.....

....T

0 1 0 2

4 4 2

S#.T

.#.#

.#.#

.#.#

0 0 0 3

2 0 2 2

输出:

6
8
-1
3

这道题跟普通dfs的区别就在于,它是有一个传送门的,那么当然不能像普通dfs一样建立一个队列,然后无脑塞进去再拿出来,因为我们塞进去的可能是通过传送门到达的地方,而dfs建队列的原则是先进入队列的一定是离起点最近的,那么传送门所带来的距离的不确定性就让我们无法正常使用queue。

但是再一想,我们关心的其实不是进入队列的顺序,因为它最终要影响的其实是出队的顺序,而出队的顺序,由该点距离起点的距离决定,既然如此,就可以建一个优先队列来存储,我们依然可以无脑塞进去,因为优先队列可以保证我们的距离始终有序。

另一个问题是如何存储传送门的起点和终点。显然,用一个vector建立邻接表就可以了。

关于优先队列的排序,我们要以到起点的距离为标准,所以可以建一个结构体,存放步数,步数就是排序的标准。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,q;
struct ty{//建立结构体
	int x,y,step;
	bool operator<(const ty& s)const{
		return step>s.step;//重载<符号
	}
};
bool vis[310][310];//标记是否走过
ty star,ed;//起终点
int dir[][4]={{1,0},{-1,0},{0,1},{0,-1}};
char mas[310][310];
vector<int> v[90010];//用一个数来存二维信息,故开一个int就可以了
bool inmap(int x,int y){
	return x>=0&&y>=0&&x<n&&y<m;
}
void bfs(){
	memset(vis,0,sizeof(vis));
	priority_queue<ty> q;
	q.push(star);
	vis[star.x][star.y]=1;
	while(!q.empty()){
		ty t=q.top();
		q.pop();
		int x=t.x,y=t.y;
		if(mas[x][y]=='T') {cout<<t.step<<endl;return;}
		for(int i=0;i<4;++i){
			int xx=x+dir[i][0];
			int yy=y+dir[i][1];
			if(inmap(xx,yy)&&!vis[xx][yy]&&mas[xx][yy]!='#'){
				vis[xx][yy]=1;
				q.push({xx,yy,t.step+1});	
			}
		}
		for(int i:v[x*n+y]){
			int a=i/n;
			int b=i%n;
			if(inmap(a,b)&&mas[a][b]!='#'&&!vis[a][b]){
				vis[a][b]=1;
				q.push({a,b,t.step+3});
			}
		}
	} 
	cout<<-1<<endl;
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	while(cin>>n>>m>>q){
		for(int i=0;i<n;++i){
			for(int j=0;j<m;++j){
				cin>>mas[i][j];
				v[i*n+j].clear();//清空vector,因为有多组样例!
				if(mas[i][j]=='S') star={i,j};
				if(mas[i][j]=='T') ed={i,j};
			}
		}
		for(int i=1;i<=q;++i){
			ty s1,s2;
			cin>>s1.x>>s1.y>>s2.x>>s2.y;
			v[(s1.x)*n+s1.y].push_back((s2.x)*n+s2.y);
		}
		bfs();
	}
	return 0;
}

因为是多组样例,要特别注意相关定义的清空包括vector、priority_queue、vis等。细节没有太多,跟普通dfs相比只是改了一个优先队列而已。

一道相关的题(状态更加复杂一些,要对vis进行变化)

优先队列+bfs why的吃鸡_sophilex的博客-优快云博客

### 迷宫问题中的广度优先搜索 (BFS) 算法 #### 定义与特性 广度优先搜索(BFS)是一种用于遍历或搜索树状图或图形结构的算法。此方法的特点是从根节点开始,沿着树的宽度移动,在每一层中尽可能深入地探索相邻子节点之前先访问同一级别的所有其他节点[^2]。 #### 主要步骤概述 对于迷宫问题而言,采用BFS意味着从入口位置作为起始点,逐步向外扩展至每一个可达的新格子,直到到达出口为止。具体操作如下: - 创建一个队列并将初始状态加入其中; - 当队列不为空时循环执行以下动作: - 取出当前队首元素并记录其坐标; - 对于该坐标的四个方向上的邻居依次尝试前进; - 如果遇到边界外或是障碍物则跳过; - 若未曾被访问过的空白区域,则将其标记为已访问,并放入队尾等待后续处理; - 终止条件:当成功抵达目标位置即结束;如果整个过程中未能触及终点说明无解。 #### Python代码实例 下面给出一段基于Python编写的简单本的BFS求解迷宫最短路径程序: ```python from collections import deque def bfs(maze, start, end): rows = len(maze) cols = len(maze[0]) directions = [(0,-1), (-1,0), (0,1), (1,0)] # 左 上 右 下 queue = deque([start]) # 初始化队列为起点 visited = set() # 记录已经访问的位置集合 path = {start: None} # 存储前驱结点以便回溯构建最终路线 while queue: current_position = queue.popleft() if current_position == end: break for d in directions: next_x, next_y = current_position[0]+d[0], current_position[1]+d[1] if not ((0 <= next_x < rows and 0 <= next_y < cols)): continue # 边界检查 if maze[next_x][next_y] != 'O' or (next_x,next_y) in visited: # 非通路/已被访问过滤掉 continue queue.append((next_x, next_y)) visited.add((next_x, next_y)) # 加入待查列表&设置成已访态 path[(next_x, next_y)] = current_position # 更新父级关系表项 route = [] step_node = end # 自终点逆向追踪直至起点形成完整轨迹链 while step_node is not None: route.insert(0,step_node) step_node = path.get(step_node) return " -> ".join(f"({x},{y})" for x,y in route) if __name__ == "__main__": grid = [ ['X','X','X','X'], ['S','O','O','E'], ['X','X','X','X'] ] print(bfs(grid,(1,0),(1,3))) ``` 这段脚本定义了一个`bfs()`函数接收三个参数——表示迷宫的地图数组、代表起点座标元组以及目的地座标元组。通过运用双端队列(`deque`)高效管理待考察顶点序列,并利用字典对象维护各处的历史连接信息从而便于事后重构实际行走线路[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值