关于这个算法的原理的可以看该推文:什么是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);
}
}