题目描述
在象棋中,马和象的移动规则分别是“马走日”和“象走田”。现给定骑士的起始坐标和目标坐标,要求根据骑士的移动规则,计算从起点到达目标点所需的最短步数。
棋盘大小 1000 x 1000(棋盘的 x 和 y 坐标均在 [1, 1000] 区间内,包含边界)
输入描述
第一行包含一个整数 n,表示测试用例的数量,1 <= n <= 100。
接下来的 n 行,每行包含四个整数 a1, a2, b1, b2,分别表示骑士的起始位置 (a1, a2) 和目标位置 (b1, b2)。
输出描述
输出共 n 行,每行输出一个整数,表示骑士从起点到目标点的最短路径长度。
输入示例
6 5 2 5 4 1 1 2 2 1 1 8 8 1 1 8 7 2 1 3 3 4 6 4 6
输出示例
2 4 6 5 1 0
[KamaCoder] 127. 骑士的攻击
自己看到题目的第一想法
遍历他, dfs 他!
看完代码随想录之后的想法
启发式搜索函数很妙, 像是套了一个壳一样. 核心思想是, 从起点开始往八个能走的方向遍历, 然后计算出下一个节点距离原点的真实路径, 再计算一下原点距离终点的距离.
计算当前节点到终点的距离有三种方法:
- 曼哈顿距离,计算方式: d = abs(x1-x2)+abs(y1-y2)
- 欧氏距离(欧拉距离) ,计算方式:d = sqrt( (x1-x2)^2 + (y1-y2)^2 )
- 切比雪夫距离,计算方式:d = max(abs(x1 - x2), abs(y1 - y2))
天启骑士需要的是欧拉公式.
核心思想是, 选择距离原点和终点最近的节点优先遍历, 直到达到终点为止.
import java.util.Scanner;
import java.util.PriorityQueue;
import java.util.Comparator;
// 几天之后依旧一次 AC
public class Main {
private static int[][] dir = {
{-2, 1}, {2, 1}, {2, -1}, {-2, -1},
{-1, 2}, {1, 2}, {1, -2}, {-1, -2}};
private static int[][] move = new int[1001][1001];
private static int startX;
private static int startY;
private static int targetX;
private static int targetY;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int pathCount = scanner.nextInt();
for (int i = 0; i < pathCount; i++) {
startX = scanner.nextInt();
startY = scanner.nextInt();
targetX = scanner.nextInt();
targetY = scanner.nextInt();
for (int j = 0; j < move.length; j++) {
for (int k = 0; k < move[j].length; k++) {
move[j][k] = 0;
}
}
astart();
System.out.println(move[targetX][targetY]);
}
}
private static void astart() {
PriorityQueue<Node> queue = new PriorityQueue<Node>(new Comparator<Node>() {
@Override
public int compare(Node node1, Node node2) {
return node1.f - node2.f;
}
});
Node node = new Node();
node.x = startX;
node.y = startY;
node.g = 0;
node.h = heuristic(node);
node.f = node.g + node.h;
queue.offer(node);
while (!queue.isEmpty()) {
Node currentNode = queue.poll();
if (currentNode.x == targetX && currentNode.y == targetY) {
return;
}
for (int i = 0; i < dir.length; i++) {
int newX = currentNode.x + dir[i][0];
int newY = currentNode.y + dir[i][1];
if (newX < 1 || newX > 1000 || newY < 1 || newY > 1000) {
continue;
}
if (move[newX][newY] != 0) {
continue;
}
Node newNode = new Node();
newNode.x = newX;
newNode.y = newY;
newNode.g = currentNode.g + 5;// 1 * 1 + 2 * 2 马走日
newNode.h = heuristic(newNode);
newNode.f = newNode.g + newNode.h;
move[newX][newY] = move[currentNode.x][currentNode.y] + 1;
queue.add(newNode);
}
}
}
private static int heuristic(Node node) {
int xLength = node.x - targetX;
int yLength = node.y - targetY;
return xLength * xLength + yLength * yLength;
}
private static class Node {
int x;// x 坐标
int y;// y 坐标
int g;// 距离原点的距离
int h;// 距离终点的距离, 欧拉距离
int f;// 当前节点的权值
}
}
自己实现过程中遇到哪些困难
无.