洛谷P1443题解:BFS算法求解马的移动问题

一、题目解读
洛谷P1443题要求计算在n×m的棋盘上,马从起点(x, y)出发,到达每个位置所需的最少移动步数。题目中“马”遵循国际象棋的移动规则(即走“日”字),需输出整个棋盘各点到起点的最短步数矩阵。该问题本质是求解多源最短路径,但考虑到马的移动特性,采用广度优先搜索(BFS)算法能高效解决。
二、解题思路
核心思路为:
1. BFS算法:利用队列存储待遍历的位置,从起点开始逐层扩散,确保首次到达某点的步数即为最短。
2. 方向数组优化:预先定义马可移动的8个方向(dx, dy),避免每次计算偏移量,提升效率。
3. 标记已访问:使用board数组记录步数,初始值-1表示未访问,避免重复计算。
4. 边界检查:在扩展新位置时,需判断是否在棋盘内且未被访问,保证算法正确性。
三、解题步骤
1. 初始化:读取棋盘尺寸n×m和起点坐标(x, y),创建board数组并初始化为-1,队列q存入起点。
2. BFS主循环:
弹出队首位置,获取其坐标和步数。
遍历8个方向,计算新坐标(nx, ny)。
若新位置合法且未访问,更新board[nx][ny]为当前步数+1,并加入队列。
3. 输出结果:遍历board数组,按格式输出每个位置的步数。
四、代码与注释
#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
// 定义马移动的8个方向
const int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1};
const int dy[8] = {2, 1, -1, -2, -2, -1, 1, 2};
int main() {
int n, m, x, y;
cin >> n >> m >> x >> y;
// 初始化棋盘,所有位置设为-1
vector<vector<int>> board(n+1, vector<int>(m+1, -1));
queue<pair<int, int>> q;
// 起点设置为0步
board[x][y] = 0;
q.push({x, y});
while (!q.empty()) {
auto current = q.front();
q.pop();
int cx = current.first;
int cy = current.second;
// 尝试8个方向
for (int i = 0; i < 8; i++) {
int nx = cx + dx[i];
int ny = cy + dy[i];
// 检查新位置是否在棋盘内且未被访问
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && board[nx][ny] == -1) {
board[nx][ny] = board[cx][cy] + 1;
q.push({nx, ny});
}
}
}
// 输出结果
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << board[i][j] << " ";
}
cout << endl;
}
return 0;
}注释说明:
● dx/dy数组:硬编码马的8个移动方向,减少重复计算。
● board初始化为-1:标记未访问状态,避免误判。
● BFS循环:通过队列逐层扩展,确保最短性。
● 边界检查:确保新位置合法,防止越界。
五、总结
本解法通过BFS算法,结合方向数组优化,实现了对马移动最短路径的高效求解。时间复杂度为O(nm),空间复杂度为O(nm),适用于大多数棋盘规模。该思路同样适用于其他类似“多源最短路径”问题,体现了BFS在图形遍历中的通用性。掌握此类算法对提升算法设计与优化能力具有重要意义。
原创内容 转载请注明出处






