题目大意
索莫罗洛夫先生确实是一位出色的国际象棋游戏者,他断言,除了他以外,没有其他人可以将骑士从一个位置如此快速地移动到另一个位置。 你能打败他吗?
问题
您的任务是编写一个程序,计算一个骑士从一个点到另一个点所需的最少移动次数,这样您就有机会比Somurolov更快。
对于不熟悉国际象棋的人,可能的骑士动作如图1所示。
思路分析
对这种走马步的问题,一般都是搜素,最难不过八数码,这道题已知起始位置和初始位置,使用双向dfs非常的合适。
#include<iostream>
#include<string.h>
#include<string>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;
#define MAX 305
#define ll int
#define p pair<int,int>
#define inf 1111111111
ll T, N;
// vis:0表示未访问,1表示正向访问,2表示逆向访问, dist:走了多少步到i,j点
ll vis[MAX][MAX], dist[MAX][MAX];
ll dx[8] = { -2,-2,-1,-1,1,1,2,2 }, dy[8] = { -1,1,-2,2,-2,2,-1,1 };
int main() {
cin >> T;
while (T--) {
cin >> N;
memset(vis, 0, sizeof(vis));
for (int i = 0; i <= N; i++)for (int j = 0; j <= N; j++)dist[i][j] = 0;
ll sx, sy, tx, ty; cin >> sx >> sy >> tx >> ty;
if (sx == tx && sy == ty) { cout << 0 << endl; continue; }
queue<p> q; ll sign = 0;
q.push(p(sx, sy)); q.push(p(tx, ty));
vis[sx][sy] = 1; vis[tx][ty] = 2;
dist[sx][sy] = 0; dist[tx][ty] = 1;
while (!q.empty() && !sign) {
ll x = q.front().first, y = q.front().second; q.pop();
for (int i = 0; i < 8; i++) {
ll xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || xx >= N || yy < 0 || yy >= N)continue;
if (vis[xx][yy] == vis[x][y]) continue;//已经和上个节点同向访问过了
else if (vis[xx][yy] + vis[x][y] == 3) {//正向反向都来了一次,结果出现
cout << dist[xx][yy] + dist[x][y] << endl;
sign = 1; break;
}
else {//从没遍历过
vis[xx][yy] = vis[x][y];//和推出他的节点保持同向
dist[xx][yy] = dist[x][y] + 1;
q.push(p(xx, yy));
}
}
}
}
}```