[贪心+搜索] 马走日升级版
题目描述
国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为 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 >= qswap(p, q);}p -= 4;if(p - 4 <= q * 2){q -= 2;}ans += 2;}bfs();//见上文,范围根据限定值来定,至少限定值加 4输出 ans + bfs 的值
}