A*启发式搜索算法

    关于这个算法的原理的可以看该推文:什么是A*寻路算法

    A*算法涉及到两个集合:openList和closeList。openList是存储当前点可达的位置,closeList是存储搜索时曾达到的点。

    公式:F = G+H;G代表起点走到当前点的成本,H代表无障碍下到达终点的成本。

    下面的搜索是只可上下左右移动,所以H = |x1 - x2| + |y1 - y2|;如果可多个斜着移动,可按着原理修改H的公式。

import java.util.*;

public class Main {
    private static class Node {
        int x;//Node的X坐标
        int y;//Node的Y坐标
        int data;//地图
        int F;
        int G;
        int H;
        Node node;//上一个节点
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("输入迷宫的大小:");
        while (sc.hasNextInt()) {
            int row = sc.nextInt();
            int col = sc.nextInt();
            Node[][] nodes = new Node[row + 1][col + 1];
            int[][] flag = new int[row + 1][col + 1];//用来标记访问过的节点和障碍
            //找相邻节点时的四个方向
            int[] xf = {0, 1, -1, 0};
            int[] yf = {1, 0, 0, -1};
            //初始化迷宫
            for (int i = 1; i <= row; i++) {
                for (int j = 1; j <= col; j++) {
                    Node node = new Node();
                    node.x = i;
                    node.y = j;
                    node.data = sc.nextInt();//0可达,1障碍
                    //标记障碍
                    if (node.data == 1)
                        flag[i][j] = 1;
                    node.node = null;
                    nodes[i][j] = node;
                }
            }

            System.out.println("输入迷宫的起点:");
            int sx = sc.nextInt();
            int sy = sc.nextInt();
            System.out.println("输入迷宫的终点:");
            int ex = sc.nextInt();
            int ey = sc.nextInt();
            List<Node> openList = new ArrayList<>();
            List<Node> closeList = new ArrayList<>();
            //起点
            Node str = nodes[sx][sy];
            str.G = 0;
            str.H = Math.abs(sx - ex) + Math.abs(sy - ey);//两个点的最短路径(不包括障碍物)。
            str.F = str.G + str.H;
            Node end = null;
            openList.add(str);
            boolean b = true;//为了找到节点后结束循环,是一个标记位
            while (openList.size() > 0 && b) {
                //找出openList中最小的F
                int min = Integer.MAX_VALUE;
                int x = 0;
                int y = 0;
                for (Node n : openList) {
                    if (n.F <= min) {
                        x = n.x;
                        y = n.y;
                        min = n.F;
                    }
                }
                Node minNode = nodes[x][y];
                flag[x][y] = 1;
                openList.remove(minNode);
                closeList.add(minNode);
                //遍历4个方向。
                for (int i = 0; i < 4; i++) {
                    int nx = x + xf[i];
                    int ny = y + yf[i];
                    //注意边界、访问过的节点、障碍物、还有openList中的节点的条件
                    if (nx >= 1 && nx <= row && ny >= 1 && ny <= col && flag[nx][ny] == 0 && !openList.contains(nodes[nx][ny])) {
                        nodes[nx][ny].G = minNode.G + 1;//上一个节点的G + 1
                        nodes[nx][ny].H = Math.abs(ex - nx) + Math.abs(ey - ny);
                        nodes[nx][ny].F = nodes[nx][ny].G + nodes[nx][ny].H;
                        nodes[nx][ny].node = minNode;//记录上一个节点,为了回溯
                        flag[nx][ny] = 1;//标记访问过该点
                        if (nx == ex && ny == ey) {//如果这个点是终点,说明可达,break这个for循环,然后把b设置成false
                            b = false;//因为break只可以结束该for,所以设置为false之后,外层循环也可结束。
                            end = nodes[nx][ny];//把终点赋值到end变量
                            break;
                        }
                        openList.add(nodes[nx][ny]);
                    }
                }
            }
            if (end == null) {//如果eng变量为null说明找不到
                System.out.println("无法找到终点");
            } else {//有的话,回溯打印路径。
                dfs(end);
            }
            System.out.println("输入迷宫的大小");
        }
    }

    public static void dfs(Node node) {
        if (node == null)
            return;
        dfs(node.node);
        System.out.println("(" + node.x + "," + node.y + ")" + " F:" + node.F);
    }
}


  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值