P2298 Mzc和男家丁的游戏 标准广搜模板
解题思路
这道题是一个典型的二维矩阵中的最短路径问题,可以使用广度优先搜索(BFS)来解决。BFS非常适合解决这种无权图的最短路径问题,因为它会逐层扩展搜索,第一次到达目标点时经历的步数就是最短路径。
关键点:
-
矩阵表示:用二维字符数组
g存储地图,包含起点'm'、终点'd'、障碍'#'和空地'.' -
BFS特性:BFS保证第一次到达终点时的步数就是最短路径
-
边界处理:需要检查移动后的坐标是否超出矩阵范围
-
访问标记:使用
vis数组避免重复访问和陷入循环
代码注释
#include<bits/stdc++.h> using namespace std; const int N = 2e3 + 10; // 定义矩阵最大尺寸 // 定义节点结构体,存储坐标和步数 struct node { int x, y, step; // x,y是坐标,step是到达该点的步数 }; char g[N][N]; // 存储地图的二维数组 int vis[N][N]; // 访问标记数组,记录是否已经访问过 int n, m; // 地图的行数和列数 int sx, sy, ex, ey; // 起点(m)和终点(d)的坐标 // 四个移动方向:右、下、左、上 int nex[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; // BFS函数,从起点(sx,sy)开始搜索 void bfs(int sx, int sy) { queue<node> q; // 创建队列用于BFS q.push({sx, sy, 0}); // 起点入队,初始步数为0 vis[sx][sy] = 1; // 标记起点已访问 while(q.size()) { // 当队列不为空时循环 node h = q.front(); q.pop(); // 取出队首元素 // 尝试四个方向移动 for(int i = 0; i < 4; i++) { int tx = nex[i][0] + h.x; // 计算新坐标x int ty = nex[i][1] + h.y; // 计算新坐标y // 边界检查:超出矩阵范围则跳过 if(tx < 1 || ty < 1 || tx > n || ty > m) continue; // 检查是否是障碍或已访问过 if(g[tx][ty] == '#' || vis[tx][ty]) continue; vis[tx][ty] = 1; // 标记为已访问 q.push({tx, ty, h.step + 1}); // 新位置入队,步数+1 // 如果到达终点 if(tx == ex && ty == ey) { cout << h.step + 1; // 输出当前步数 return; // 直接返回 } } } // 如果队列为空仍未找到终点,输出无解 cout << "No Way!"; } int main() { // 读取输入 cin >> n >> m; // 读取地图数据 for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { cin >> g[i][j]; if(g[i][j] == 'm') sx = i, sy = j; // 记录起点坐标 if(g[i][j] == 'd') ex = i, ey = j; // 记录终点坐标 } // 执行BFS搜索 bfs(sx, sy); return 0; }
算法分析
-
时间复杂度:O(n×m),最坏情况下需要遍历整个矩阵
-
空间复杂度:O(n×m),用于存储访问标记和队列
-
优化考虑:
-
可以使用双向BFS进一步优化性能
-
对于大型矩阵,可以考虑使用更高效的数据结构
-
提前终止条件:找到终点立即返回
-
注意事项
-
题目中矩阵的行列索引从1开始
-
题目要求1秒内完成,对于2000×2000的矩阵,常规BFS在C++中是可以接受的
-
障碍物'#'和访问标记
vis都需要检查,避免重复计算

浙公网安备 33010602011771号