洛谷P1747题解:遍历最短路径(BFS算法优化)

一、题目解读
洛谷P1747题目要求模拟中国象棋中“马”的移动规则,计算从任意起点到终点所需的最小步数。题目中马的移动方式包括传统的“日”字步(8种方向)及特殊“田”字步(4种方向),需在限定范围内寻找最短路径。问题核心在于利用图论算法解决多方向移动的最短路径问题。
二、解题思路
采用**广度优先搜索(BFS)**算法,其核心思想是逐层遍历所有可能状态,直到找到目标点。由于马的移动具有多种方向,需预先定义12种偏移量(dx、dy数组),通过队列维护待扩展节点。每次从队列取出当前节点,尝试所有合法移动方向,标记已访问状态并更新步数,直至到达终点。该算法保证首次到达终点的路径即为最短路径。
三、解题步骤
1. 初始化:定义队列q,访问标记visited数组,将起点入队并标记访问。
2. BFS循环:
取出队头节点(当前位置及步数)。
遍历12种移动方向,计算新坐标(nx, ny)。
判断新坐标是否越界或已访问,若合法:
若为新终点,返回当前步数+1;
否则标记visited并加入队列,步数+1。
3. 终止条件:队列为空时,返回-1(理论上不会执行)。
四、代码与注释
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 50; // 棋盘最大范围
const int dx[] = {-2,-2,-1,-1,1,1,2,2,-2,2,-2,2};
const int dy[] = {-1,1,-2,2,-2,2,-1,1,-2,-2,2,2};
// 节点结构(坐标+步数)
struct Point {
int x, y, steps;
};
// 核心BFS函数
int bfs(int startX, int startY) {
if(startX == 1 && startY == 1) return 0; // 起点即终点直接返回0
queue<Point> q;
bool visited[MAXN][MAXN] = {false};
q.push({startX, startY, 0}); // 起点入队
visited[startX][startY] = true;
while(!q.empty()) {
Point current = q.front(); // 取出当前节点
q.pop();
for(int i = 0; i < 12; i++) { // 遍历12种移动方向
int nx = current.x + dx[i];
int ny = current.y + dy[i];
if(nx < 1 || ny < 1 || nx >= MAXN || ny >= MAXN) continue; // 越界判断
if(visited[nx][ny]) continue; // 已访问跳过
if(nx == 1 && ny == 1) { // 到达终点
return current.steps + 1;
}
visited[nx][ny] = true; // 标记访问
q.push({nx, ny, current.steps + 1}); // 新节点入队
}
}
return -1; // 理论上不会执行到这里
}
int main() {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2; // 输入两个起点坐标
cout << bfs(x1, y1) << endl; // 输出两起点的最短路径
cout << bfs(x2, y2) << endl;
return 0;
}五、总结
本解法利用BFS算法的“逐层扩散”特性,结合象棋马的多方向移动特点,通过预定义偏移量简化方向计算。算法时间复杂度为O(n^2),空间复杂度O(n^2)(标记数组),适用于求解中小规模棋盘的最短路径问题。在实际应用中,BFS常用于寻找无权图的最短路径,其简洁性与效率使其成为图论基础算法之一。
原创内容 转载请注明出处






