马步距离-NOIP 模拟赛-BFS

题目描述

在国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为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;
}
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值