题目描述
在国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为0的点出发,可以经过一步马步移动达到标号为1的点,经过两步马步移动达到标号为2的点。
在国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为0的点出发,可以经过一步马步移动达到标号为1的点,经过两步马步移动达到标号为2的点。
任给平面上的两点p和s,它们的坐标分别为(xp,yp)和(xs,ys),其中,xp,yp,xs,ys均为整数。从(xp,yp)出发经过一步马步移动 可以达到(xp+1,yp+2)、(xp+2,yp+1)、(xp+1,yp-2)、(xp+2,yp-1)、(xp-1,yp+2)、(xp- 2,yp+1)、(xp-1,yp-2)、(xp-2,yp-1)。假设棋盘充分大,并且坐标可以为负数。现在请你求出从点p到点s 至少需要经过多少次马步移动?
样例
输入:
①-311 -313 3134 32321 ② 0 0 1 1
输出:
①16317 ② 2
这俩样例能过你能过
这道题的最核心的地方不在于 你的bfs写法,而在于bfs的剪枝,称为剪枝可能不太合适,但是确实是要把你要跳的位置和你的位置尽可能地缩短距离,让搜索的次数大大减少。
符合新手初学bfs时的惯用套路与写法。
代码:
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0);
#define int long long
using namespace std;
const int N = 35;
const int INF = 0x3f3f3f3f;
int dir[8][2] = {{1, 2}, {1, -2}, {-1, 2}, {-1, -2}, {2, 1}, {2, -1}, {-2, 1}, {-2, -1}};
int sx, sy, ex, ey, maxx, maxy, xx, yy, ans;
struct node
{
int x, y, step;
};
map<int, int>mp[100];
queue<node> q;
void bfs(int x, int y)
{
node p;
q.push({x, y, 0});
while (!q.empty())
{
p = q.front();
if (p.x == xx && p.y == yy)
{
cout << p.step + ans;
break;
}
q.pop();
for (int i = 0; i < 8; i++)
{
int dx = p.x + dir[i][0];
int dy = p.y + dir[i][1];
if (dx >= 0 && dx <= 100 && dy >= 0 && dy <= 100 && mp[dx][dy] == 0) //
{
mp[dx][dy] = 1;
q.push({dx, dy, p.step + 1});
}
}
}
}
signed main()
{
cin >> sx >> sy >> ex >> ey;
if (ex > 0)ex++;
else ex--;
if (ey > 0)ey++;
else ey--;
//注意这里,对应最下面的bfs(1,1),让从1,1开始搜索避免坐标为负数组无法标记而崩溃
//而正负判断是最重要的,被这个点卡了一次,正增负减是为了下面算距离的绝对值,你
//初始位置横纵坐标都增加了1,为了使距离的绝对值不变你的目标位置横纵坐标也要改变
xx = abs(sx - ex);
yy = abs(sy - ey);
while (xx >= 20 || yy >= 20)//简单朴素的缩短距离方法,如果换成横坐标或纵坐标一次跳两下也是可以的
{
if (xx > yy)xx -= 2, yy -= 1;
else xx -= 1, yy -= 2;
ans++;
xx = abs(xx);
yy = abs(yy);
}
bfs(1, 1);
return 0;
}