1915:Knight Moves:已知始末状态的马步棋盘问题,双向bfs效率KO

题目大意

索莫罗洛夫先生确实是一位出色的国际象棋游戏者,他断言,除了他以外,没有其他人可以将骑士从一个位置如此快速地移动到另一个位置。 你能打败他吗?

问题

您的任务是编写一个程序,计算一个骑士从一个点到另一个点所需的最少移动次数,这样您就有机会比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));
				}
			}
		}
	}
}```

发布了211 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/csyifanZhang/article/details/105340031
今日推荐