题目
- 参考网址:https://vjudge.net/problem/UVA-439
- 大意:
按照国际象棋🐴的移动规则,求🐴最小需要多少步从起点跳到终点。(老BFS模板题了~)
知识点
- BFS求最短路径
思路
BFS模板题,输入转换为坐标r (row),c (column)行和列,使用队列的方式进行BFS,使用vis记录是否访问,使用dis记录距离(当然两个可以合并为一个来写)。
- 每次pop出队首u检查是否是目的位置,是的话返回当前节点位置所记录下的dis。
- 否则,向“四面八方”扩散出去,判断条件为即不超出边界,且没有访问过 (is_ok(r1, c1) && !vis[r1][c1])。(访问过再走一边相当于绕圈子了,肯定不是最短路径)如果满足条件,将该状态所在的位置的dis更新为dis[u] + 1(距离+1),vis[当前位置]打上标记然后入队,每次循环检查队列是否为空,如果队列为空,仍然没有找到目的位置,则说明无解(当然这道题是不可能有无解的)。
- 状态的记录建议用个结构体,我用了数组记录,debug了半天,问题在后续有记录!!
代码
# include <iostream>
# include <queue>
using namespace std;
string alphabet = "abcdefg"; // 用于映射 0-7
int end_r, end_c; // 结束坐标
int dr[] = {1, 2, 2, 1, -1, -2, -2, -1}; // 顺时针
int dc[] = {-2, -1, 1, 2, 2, 1, -1, -2};
int vis[8][8], dis[8][8]; // 记录访问 & 距离
queue<int *> q; // 状态以status[1][1]的方式存入
bool is_ok(int r, int c) { // 检查是否超出边界
return r >= 0 && r < 8 && c >= 0 && c < 8;
}
int bfs(int r, int c) {
int status[] = {r, c};
q.push(status);
vis[r][c] = 1; // 初始起点标记为访问过
dis[r][c] = 0; // 起始点距离为0
while (!q.empty()) { // 队列不为空
int *u = q.front(); q.pop(); // pop出队头
// 判断是否已经是目的位置,是的话返回结果即可
if (u[0] == end_r && u[1] == end_c)
return dis[u[0]][u[1]];
for (int i = 0; i < 8; i++) {
int r1 = u[0] + dr[i];
int c1 = u[1] + dc[i];
if (is_ok(r1, c1) && !vis[r1][c1]) {
// 可以移动且没有访问过(访问过的绕回来再走没有意义,徒增dis)
int *temp = new int[2]{r1, c1};
// !这里不能直接 int temp[2] = {r1, c1}; 不然每次地址都一样会被覆盖掉
vis[r1][c1] = 1; // 标记为“已经访问过”
dis[r1][c1] = dis[u[0]][u[1]] + 1; // 距离更新
q.push(temp); // 入队
}
}
}
}
int main() {
// 输入 & 初始化
char input[4];
cin >> input[0] >> input[1];
cin >> input[2] >> input[3];
int start_r = input[1] - 49;
int start_c = find(alphabet.begin(), alphabet.end(), input[0]) - alphabet.begin(); // 映射为 0-7
end_r = input[3] - 49;
end_c = find(alphabet.begin(), alphabet.end(), input[2]) - alphabet.begin(); // 映射为 0-7
memset(vis, 0, sizeof(int[8][8])); // 初始化
memset(dis, -1, sizeof(int[8][8]));
// bfs得到最小路径
int ans = bfs(start_r, start_c);
cout << "To get from " << alphabet[start_c] <<start_r + 1 << " to "
<< alphabet[start_c] << end_r + 1 << " takes " << ans << " knight moves." << endl;
return 0;
}
过程中遇到的问题 & 解决
- BFS求最短路径没什么好说,唯一一个调了半天的bug是
int *temp = new int[2]{r1, c1};
这一句,不能直接int temp[2] = {r1, c1};
。不然的话会覆盖上一个地址,有点百思不得其解这个编译时候的逻辑QAQ。
测试
输入:
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
结果:✔️
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.