问题描述
小U掌握了国际象棋中“象”和“马”的跳跃能力,在一个无限大的平面直角坐标系中,她每一步可以模仿象和马的跳跃方式移动。在每次询问中,小U需要计算从初始坐标 (x1,y1)(x1,y1) 到 (x2,y2)(x2,y2) 所需的最少步数。
- 象的跳跃:可以移动到 (x+k,y+k)(x+k,y+k) 或 (x+k,y−k)(x+k,y−k),其中 kk 是任意整数。
- 马的跳跃:可以移动到 (x+a,y+b)(x+a,y+b),其中 ∣a∣+∣b∣=3∣a∣+∣b∣=3 且 1≤∣a∣,∣b∣≤21≤∣a∣,∣b∣≤2。
你需要在每次询问中计算从起点到终点所需的最少步数。
思路
首先,观察到总是可以在不超过3步从任意起点到达终点。
因为,想象分别以(x1,y1),(x2,y2)为中心点划出“象”可以走的斜线,两者必然有交点(x3,y3)。 如果(x3,y3)正好是整数,则可以(x1,y1) ->(x3,y3)-> (x2,y2) 不超过两步到达终点。 如果(x3,y3)为整数,代数显示这当且仅当 (x1-x2) + (y1-y2)是一个奇数,则可以通过马随便跳一步后,使得上式成为偶数,从而不超过三步到达终点。
所以,仅需要考虑3步以下的情况。
进一步发现,如move1,move2, move3 从(x1,y1) 到达(x2,y2), 那这些move的任何次序(例:move2, move1, move3)同样可以到达。
所以,可以穷举出:
- 0步到达情况:起点等于终点
- 1步到达情况:马, 象
- 2步到达的情况:马马,马象,象象
根据以上的情况分类讨论即可
代码示例
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
bool on_same_line(int x1, int y1, int x2, int y2) {
return abs(x1-x2) == abs(y1 - y2);
}
bool is_same_point(int x1, int y1, int x2, int y2) {
return x1 == x2 && y1 == y2;
}
bool on_bended_line(int x1, int y1, int x2, int y2) {
return (x1+y1-x2-y2)%2 == 0;
}
int solution(int x1, int y1, int x2, int y2) {
if (is_same_point(x1,y1,x2,y2)) {
return 0;
}
if(on_same_line(x1,y1,x2,y2)) {
return 1;
}
vector<pair<int,int>> moves;
for(int i=-1;i<2;i+=2) {
for(int j=-1;j<2;j+=2) {
moves.push_back({i,2*j});
moves.push_back({2*i,j});
}
}
for(auto m: moves) {
int x3 = x1 + m.first;
int y3 = y1 + m.second;
if(is_same_point(x3,y3,x2,y2)) {
return 1;
}
}
if(on_bended_line(x1,y1,x2,y2)) {
return 2;
}
for(auto m: moves) {
int x3 = x1 + m.first;
int y3 = y1 + m.second;
if(on_same_line(x3,y3,x2,y2)) {
return 2;
}
for(auto m: moves) {
int x4 = x3 + m.first;
int y4 = y3 + m.second;
if(is_same_point(x4,y4,x2,y2)) {
return 2;
}
}
}
return 3;
}