Problem: 无链接
文章目录
- 思路
- 解题方法
- 复杂度
- Code
思路
这是一个经典的A寻路算法问题。A算法是一种启发式搜索算法,题解结合了最佳优先搜索和Dijkstra算法的优点,能够在寻找最短路径的过程中避免大量的无谓搜索,提高了效率。
在这个问题中,我们需要找到从起点到终点的最短路径。我们可以使用A*算法,通过一个优先队列(堆)来存储待搜索的节点,每次从堆中取出代价最小的节点进行搜索,直到找到终点。
解题方法
首先,我们需要定义一个二维数组distance,用来存储从起点到每个点的最短距离。初始时,所有点的距离都设为无穷大,只有起点的距离设为0。
然后,我们定义一个优先队列heap,用来存储待搜索的节点。每个节点的代价由两部分组成:从起点到该节点的已知最短距离,以及该节点到终点的估计距离(启发式函数)。我们每次从堆中取出代价最小的节点进行搜索。
在搜索过程中,我们需要更新每个节点的最短距离,并将其邻居节点加入到堆中。如果某个节点已经被访问过,那么我们就不需要再次访问它。
最后,当我们找到终点时,就可以返回其最短距离了。
复杂度
时间复杂度:
O ( n 2 l o g n ) O(n^2 log n) O(n2logn),其中n是网格的大小。这是因为在最坏的情况下,我们需要访问网格中的每个节点,并在堆中进行插入和删除操作。
空间复杂度:
O ( n 2 ) O(n^2) O(n2),主要是因为我们需要存储每个节点的最短距离和访问状态。
Code
import java.util.PriorityQueue;public class AStarAlgorithm {public static int[] move = { -1, 0, 1, 0, -1 };public static int minDistance1(int[][] grid, int startX, int startY, int targetX, int targetY) {if (grid[startX][startY] == 0 || grid[targetX][targetY] == 0) {return -1;}int n = grid.length;int m = grid[0].length;boolean[][] vis = new boolean[n][m];int[][] distance = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {distance[i][j] = Integer.MAX_VALUE;}}distance[startX][startY] = 1;PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[2] - b[2]);heap.add(new int[] { startX, startY, distance[startX][startY] });while (!heap.isEmpty()) {int[] records = heap.poll();int x = records[0];int y = records[1];if (vis[x][y]) {continue;}vis[x][y] = true;if (x == targetX && y == targetY) {return distance[x][y];}// 开枝散叶for (int i = 0; i < 4; i++) {int nx = x + move[i];int ny = y + move[i + 1];if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny] && grid[nx][ny] == 1&& distance[x][y] + 1 < distance[nx][ny]) {distance[nx][ny] = distance[x][y] + 1;heap.add(new int[] { nx, ny, distance[nx][ny] });}}}return -1;}public static int minDistance2(int[][] grid, int startX, int startY, int targetX, int targetY) {if (grid[startX][startY] == 0 || grid[targetX][targetY] == 0) {return -1;}int n = grid.length;int m = grid[0].length;boolean[][] vis = new boolean[n][m];int[][] distance = new int[n][m];for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {distance[i][j] = Integer.MAX_VALUE;}}distance[startX][startY] = 1;PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[2] - b[2]);heap.add(new int[] { startX, startY, 1 + f1(startX, startY, targetX, targetY) });while (!heap.isEmpty()) {int[] record = heap.poll();int x = record[0];int y = record[1];if (vis[x][y]) {continue;}vis[x][y] = true;if (x == targetX && y == targetY) {return distance[x][y];}// 开枝散叶for (int i = 0; i < 4; i++) {int nx = x + move[i];int ny = y + move[i + 1];if (nx >= 0 && ny >= 0 && nx < n && ny < m && !vis[nx][ny] && grid[nx][ny] == 1&& distance[x][y] + 1 < distance[nx][ny]) {distance[nx][ny] = distance[x][y] + 1;heap.add(new int[] { nx, ny, distance[nx][ny] + f1(nx, ny, targetX, targetY) });}}}return -1;}// 曼哈顿距离public static int f1(int x, int y, int targetX, int targetY) {return (Math.abs(targetX - x) + Math.abs(targetY - y));}// 对角线距离public static int f2(int x, int y, int targetX, int targetY) {return Math.max(Math.abs(targetX - x), Math.abs(targetY - y));}// 欧式距离public static double f3(int x, int y, int targetX, int targetY) {return Math.sqrt(Math.pow(targetX - x, 2) + Math.pow(targetY - y, 2));}// 为了测试public static int[][] randomGrid(int n) {int[][] grid = new int[n][n];for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (Math.random() < 0.3) {// 每个格子有30%概率是0grid[i][j] = 0;} else {// 每个格子有70%概率是1grid[i][j] = 1;}}}return grid;}// 为了测试public static void main(String[] args) {int len = 100;int testTime = 10000;System.out.println("功能测试开始");for (int i = 0; i < testTime; i++) {int n = (int) (Math.random() * len) + 2;int[][] grid = randomGrid(n);int startX = (int) (Math.random() * n);int startY = (int) (Math.random() * n);int targetX = (int) (Math.random() * n);int targetY = (int) (Math.random() * n);int ans1 = minDistance1(grid, startX, startY, targetX, targetY);int ans2 = minDistance2(grid, startX, startY, targetX, targetY);if (ans1 != ans2) {System.out.println("出错了!");}}System.out.println("功能测试结束");System.out.println("性能测试开始");int[][] grid = randomGrid(4000);int startX = 0;int startY = 0;int targetX = 3900;int targetY = 3900;long start, end;start = System.currentTimeMillis();int ans1 = minDistance1(grid, startX, startY, targetX, targetY);end = System.currentTimeMillis();System.out.println("运行dijskra算法结果: " + ans1 + ", 运行时间(毫秒) : " + (end - start));start = System.currentTimeMillis();int ans2 = minDistance2(grid, startX, startY, targetX, targetY);end = System.currentTimeMillis();System.out.println("运行A*算法结果: " + ans2 + ", 运行时间(毫秒) : " + (end - start));System.out.println("性能测试结束");}}