代码随想录算法训练营第六十二天| 127. 骑士的攻击 (Astar 算法)

[KamaCoder] 127. 骑士的攻击

[KamaCoder] 127. 骑士的攻击 文章解释

题目描述

在象棋中,马和象的移动规则分别是“马走日”和“象走田”。现给定骑士的起始坐标和目标坐标,要求根据骑士的移动规则,计算从起点到达目标点所需的最短步数。

棋盘大小 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 他!

看完代码随想录之后的想法

    启发式搜索函数很妙, 像是套了一个壳一样. 核心思想是, 从起点开始往八个能走的方向遍历, 然后计算出下一个节点距离原点的真实路径, 再计算一下原点距离终点的距离.

    计算当前节点到终点的距离有三种方法:

  1. 曼哈顿距离,计算方式: d = abs(x1-x2)+abs(y1-y2)
  2. 欧氏距离(欧拉距离) ,计算方式:d = sqrt( (x1-x2)^2 + (y1-y2)^2 )
  3. 切比雪夫距离,计算方式: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;// 当前节点的权值
    }
}

自己实现过程中遇到哪些困难 

    无.

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值