题目大意
一个棋盘有八行八列,给出起点和终点求骑士的最小移动步骤。
解题思路
如果使用前面的bfs应该也是可以的,但是我们从双向bfs的思路出发。
由于起点和终点都很明确,因此我们可以从起点和终点分别bfs,当两个bfs在扩展时出现重复扩展的状态,表明从起点出发和从终点出发的两条路径连通,根据bfs的性质(在队首的一定是扩展次数少的)可以得到此时骑士移动的次数就是最少次数,搜索结束。
源代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int MAX_SIZE = 10 + 5;
struct node {
int x, y;
} st, ed;
const int dx[] = {-2, -1, -2, -1, 1, 2, 2, 1};
const int dy[] = {-1, -2, 1, 2, -2, -1, 1, 2};
int dist[MAX_SIZE][MAX_SIZE];
int vis[MAX_SIZE][MAX_SIZE];
bool is_point_in(const node &next) {
return next.x >= 1 && next.x < 9 && next.y >= 0 && next.y < 8;
}
int bfs() {
queue<node> que;
memset(dist, -1, sizeof(dist));
memset(vis, -1, sizeof(vis));
que.push(st);
que.push(ed);
dist[st.x][st.y] = dist[ed.x][ed.y] = 0;
vis[st.x][st.y] = 1;
vis[ed.x][ed.y] = 2;
while (!que.empty()) {
node k = que.front();
que.pop();
for (int i = 0; i < 8; i++) {
node next = k;
next.x += dx[i];
next.y += dy[i];
if (is_point_in(next)) {
if (vis[next.x][next.y] == -1) {
vis[next.x][next.y] = vis[k.x][k.y];
dist[next.x][next.y] = dist[k.x][k.y] + 1;
que.push(next);
} else if (vis[next.x][next.y] != vis[k.x][k.y]) {
return dist[next.x][next.y] + dist[k.x][k.y] + 1;
}
}
}
}
}
int main() {
char a[5], b[5];
while (scanf("%s%s", a, b) != EOF) {
st.x = a[1] - '0';
st.y = a[0] - 'a';
ed.x = b[1] - '0';
ed.y = b[0] - 'a';
if (st.x == ed.x && st.y == ed.y) {
printf("To get from %s to %s takes 0 knight moves.\n", a, b);
} else {
printf("To get from %s to %s takes %d knight moves.\n", a, b, bfs());
}
}
return 0;
}