题目描述
国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为 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,yp−2),(xp+2,yp−1),(xp−1,yp+2),(xp−2,yp+1),(xp−1,yp−2),(xp−2,yp−1)。假设棋盘充分大,并且坐标可以为负数。现在请你求出从点 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|
∣xp−sp∣,
y
y
y 为
∣
y
p
−
s
p
∣
|y_p - s_p|
∣yp−sp∣。始终让
x
≥
y
x \ge y
x≥y。
对于
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 的值
}