[贪心+搜索] 马走日升级版

题目描述

国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为 0 0 0 的点出发,可以经过一步马步移动达到标号为 1 1 1 的点,经过两步马步移动达到标号为 2 2 2 的点。

任给平面上的两点 p p p s s s,它们的坐标分别为 ( x p , y p ) (x_p, y_p) (xp,yp) ( x q , y q ) (x_q, y_q) (xq,yq),其中 x p , y p , x q , y q x_p, y_p, x_q, y_q xp,yp,xq,yq 均为整数。从 ( x p , y p ) (x_p, y_p) (xp,yp) 出发经过一步马步移动可以达到 ( x p + 1 , y p + 2 ) , ( x p + 2 , y p + 1 ) , ( x p + 1 , y p − 2 ) , ( x p + 2 , y p − 1 ) , ( x p − 1 , y p + 2 ) , ( x p − 2 , y p + 1 ) , ( x p − 1 , y p − 2 ) , ( x p − 2 , y p − 1 ) (x_p + 1, y_p + 2), (x_p + 2, y_p + 1), (x_p + 1, y_p - 2), (x_p + 2, y_p - 1), (x_p - 1, y_p + 2), (x_p - 2, y_p + 1), (x_p - 1, y_p - 2), (x_p - 2, y_p - 1) (xp+1,yp+2),(xp+2,yp+1),(xp+1,yp2),(xp+2,yp1),(xp1,yp+2),(xp2,yp+1),(xp1,yp2),(xp2,yp1)。假设棋盘充分大,并且坐标可以为负数。现在请你求出从点 p p p 到点 s s s 至少需要经过多少次马步移动。

输入格式

一行包括 4 4 4 个整数 x p , y p , s p , s q x_p, y_p, s_p, s_q xp,yp,sp,sq

输出格式

含一个整数,表示从点 p p p 到点 s s s 至少需要经过的马步移动次数。

样例

样例输入1:

1 2 7 9

样例输出1:

5

数据范围

对于 40 % 40\% 40% 的数据: x p , y p , x s , y s x_p,y_p,x_s,y_s xp,yp,xs,ys 的绝对值都小于 100 100 100
对于 60 % 60\% 60% 的数据: x p , y p , x s , y s x_p,y_p,x_s,y_s xp,yp,xs,ys 的绝对值都小于 1 0 6 10^6 106
对于 100 % 100\% 100% 的数据: x p , y p , x s , y s x_p,y_p,x_s,y_s xp,yp,xs,ys 的绝对值都小于 1 0 7 10^7 107

题解

对于 40 % 40\% 40% 的数据,可以直接搜索(即普通的马走日)。

#include<bits/stdc++.h>
using namespace std;
int x, y, n, m;
int p, q;
struct node{
	int u, v, step;//x, y, 步数
};
queue<node> qr;
int dx[8] = {1, -1, 2, -2, 1, -1, 2, -2};
int dy[8] = {2, -2, 1, -1, -2, 2, -1, 1};
map<pair<int, int>, int> fl;
int ans = 0;
int main(){
//	p 是 x 的差,q 是 y 的差
	p = abs(n - x);
	q = abs(m - y);
	qr.push(node{0, 0, 0});
	while(!qr.empty()){
		node t = qr.front();
//		printf("%d %d %d\n", t.u, t.v, t.step);
		if(t.u == p && t.v == q){//搜到了
			printf("%d", t.step + ans); 
			return 0;
		}
		fl[make_pair(t.u, t.v)] = 1;
		qr.pop();
		for(int i = 0; i < 8; ++ i){
			int tx = t.u + dx[i];
			int ty = t.v + dy[i];
			if (tx, ty) 没有走过且再范围内
				qr.push({tx, ty, t.step + 1});
		}
	}

对于 100 % 100\% 100% 的数据,考虑将搜索的范围减小。

x x x ∣ x p − s p ∣ |x_p - s_p| xpsp y y y ∣ y p − s p ∣ |y_p - s_p| ypsp。始终让 x ≥ y x \ge y xy
对于 x x x y y y 大于限定值(不要小于 8 8 8)的情况, x x x 先减少 4 4 4(即向该方向移动 2 2 2 步, y y y 可以不变,由于有限定值的限制,所以不用判断)。如果 y y y 走到需要跳的时候(先不动 y y y,需要时再动,移动 2 2 2 步, y y y 可以减少 2 2 2), y y y 减少 2 2 2

接下来搜索就很简单了,建议使用广搜。

代码:

int x, y, n, m;
int p, q;
int ans = 0;
int main(){
	scanf("%d %d %d %d", &x, &y, &n, &m);
	p = abs(n - x);
	q = abs(m - y);
	while(p + q >= 20){
		if(p < q){//保持 p >= q
			swap(p, q);
		}
		p -= 4;
		if(p - 4 <= q * 2){
			q -= 2;
		}
		ans += 2;
	}
	bfs();//见上文,范围根据限定值来定,至少限定值加 4
	输出 ans + bfs 的值
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值