Leetcode1368. 使网格图至少有一条有效路径的最小代价-----Dijkstra 算法、BFS

题目表述

给你一个 m x n 的网格图 grid 。 grid 中每个格子都有一个数字,对应着从该格子出发下一步走的方向。 grid[i][j] 中的数字可能为以下几种情况:

  • 1 ,下一步往右走,也就是你会从 grid[i][j] 走到 grid[i][j + 1]
  • 2 ,下一步往左走,也就是你会从 grid[i][j] 走到 grid[i][j - 1]
  • 3 ,下一步往下走,也就是你会从 grid[i][j] 走到 grid[i + 1][j]
  • 4 ,下一步往上走,也就是你会从 grid[i][j] 走到 grid[i - 1][j]
    注意网格图中可能会有 无效数字 ,因为它们可能指向 grid 以外的区域。

一开始,你会从最左上角的格子 (0,0) 出发。我们定义一条 有效路径 为从格子 (0,0) 出发,每一步都顺着数字对应方向走,最终在最右下角的格子 (m - 1, n - 1) 结束的路径。有效路径 不需要是最短路径 。

你可以花费 cost = 1 的代价修改一个格子中的数字,但每个格子中的数字 只能修改一次 。

请你返回让网格图至少有一条有效路径的最小代价。

示例:
输入:grid = [[1,1,1,1],[2,2,2,2],[1,1,1,1],[2,2,2,2]]
输出:3
解释:你将从点 (0, 0) 出发。
到达 (3, 3) 的路径为: (0, 0) --> (0, 1) --> (0, 2) --> (0, 3) 花费代价 cost = 1 使方向向下 --> (1, 3) --> (1, 2) --> (1, 1) --> (1, 0) 花费代价 cost = 1 使方向向下 --> (2, 0) --> (2, 1) --> (2, 2) --> (2, 3) 花费代价 cost = 1 使方向向下 --> (3, 3)
总花费为 cost = 3.

0-1广度优先搜索

多源BFS:从多个节点出发,每个节点入队一次,用size记录每一层的节点数,一次访问每一层的节点。多个路径同时搜索。
普通BFS:从单个节点出发,每个节点入队一次,直到找到路径
0-1BFS:在常规的广度优先搜索中,每个节点最多被添加进队列一次,而在 0-1 广度优先搜索中,每个节点最多被添加进双端队列两次(即队首一次,队尾一次)。因为我们求的是最短路径,所以当第一次出队列时,就将该节点标记为已读,第二次出队列时就不用再处理了。英雌需要用到visited数组记录,和Dijkstra 算法很相似。

class Solution {
    public int minCost(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        Deque<int[]> que = new ArrayDeque<>();
        que.add(new int[]{0,0});
        int[][] dirs = new int[][]{{0,1},{0,-1},{1,0},{-1,0}};
        int[][] dis = new int[m][n];
        for(int i = 0; i < m;i++){
            Arrays.fill(dis[i], Integer.MAX_VALUE);
        }
        dis[0][0] = 0;
        boolean[][] visited  = new boolean[m][n];
        while(!que.isEmpty()){
            int[] cur = que.poll();
            int curx = cur[0];
            int cury = cur[1];
            if(visited[curx][cury]) continue;
            visited[curx][cury] = true;
            int i = 1;
            for (int[] dir:dirs){
                int x = dir[0] + curx;
                int y = dir[1] + cury;
                if(x < 0 || y<0|| x >= m || y>=n) continue;
                int cost = i == grid[curx][cury] ? 0 : 1;
                if(dis[curx][cury] + cost <= dis[x][y])
                    dis[x][y] = dis[curx][cury] + cost;
                else continue;
                if (cost == 0){
                    que.addFirst(new int[]{x,y});
                }else{
                    que.addLast(new int[]{x,y});
                }
                i++;
            }
        }
        return dis[m-1][n-1];
    }
}

Dijkstra 算法

class Solution {
    public int minCost(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] dis = new int[m][n];
        for(int i = 0; i < m; i++){
            Arrays.fill(dis[i], Integer.MAX_VALUE);
        }
        dis[0][0] = 0;
        boolean[][] visited = new boolean[m][n];
        int[][] dirs = {{0,1}, {0,-1},{1,0}, {-1,0}};
        PriorityQueue<int[]> que = new PriorityQueue<>((a,b)->{return a[2] - b[2];});
        que.offer(new int[]{0,0,0});
        while(!que.isEmpty()){
            int[] cur = que.poll();
            if(visited[cur[0]][cur[1]]) continue;
            visited[cur[0]][cur[1]] = true;
            for(int i = 1;i <= 4;i++){
                int x = dirs[i-1][0] + cur[0];
                int y = dirs[i-1][1] + cur[1];
                if(x < 0 || y < 0 || x>= m || y>= n) continue;
                int cost = 0;
                if(i != grid[cur[0]][cur[1]]) cost = 1;
                if(cost + cur[2] < dis[x][y]){
                    dis[x][y] = cost + cur[2];
                    que.offer(new int[]{x,y,dis[x][y]});
                }
            }
        }
        return dis[m-1][n-1];
    }
}
posted @ 2022-06-05 14:34  YoungerWb  阅读(39)  评论(0编辑  收藏  举报