leetcode1368. 使网格图至少有一条有效路径的最小代价(困难,dijkstra)

leetcode1368. 使网格图至少有一条有效路径的最小代价(困难,dijkstra)_第1张图片
leetcode1368. 使网格图至少有一条有效路径的最小代价(困难,dijkstra)_第2张图片
leetcode1368. 使网格图至少有一条有效路径的最小代价(困难,dijkstra)_第3张图片
leetcode1368. 使网格图至少有一条有效路径的最小代价(困难,dijkstra)_第4张图片
向右或者向下移动的话,就能用dp,这里是四个方向,只能用图来做。

思路:dijkstra
时间复杂度O((M+N)logM),其中 N 和 M 分别是图中的点数(nm)和边数 (4n*m)

我们可以将数组建模成一个包含 n * m 个节点和不超过 4 * m * n 条边的有向图 G。图 G 中的每一个节点表示数组 中的一个位置,它会向不超过 4 个相邻的节点各连出一条边,边的权值要么为 0(移动方向与箭头方向一致),要么为 1(移动方向与箭头方向不一致);
我们在图 G 上使用一种最短路算法,求出从 (0,0) 到 (m - 1, n - 1 的最短路,即可得到答案。

难点:方向怎么判断一致?
题目里的1 2 3 4对应(i+1)分别对应右左下上
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; // 遍历到i时得到新位置(xx, yy) ,如果i + 1 == grid[x][y]则表示方向一致

class Solution {
public:
     
    int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};  //
    using PII = pair<int, int>; //first为距离, second为位置 
    int minCost(vector<vector<int>>& grid) {
 
        int n = grid.size(), m = grid[0].size();
        vector<int> dis(n * m, INT_MAX);
        vector<int> vis(n * m, false);
        dis[0] = 0; 
        priority_queue<PII, vector<PII>, greater<PII>> pq;
        pq.emplace(0, 0);
        while (!pq.empty()) {
            auto [dis, pos] = pq.top();
            pq.pop();
            if (vis[pos]) continue;
            vis[pos] = true;
            int x = pos / m;
            int y = pos % m;
            for (int i = 0; i < 4; ++i) {
                int xx = x + dir[i][0];
                int yy = y + dir[i][1];
                int newpos = xx * m + yy;
                int _dis = dis + (grid[x][y] != i + 1);
                if (xx >= 0 && xx < n && yy >= 0 && yy < m && d[newpos] > _dis) {
                    dis[newpos] = _dis;
                    pq.emplace(dis[newpos], newpos);
                }  
            }
        }
        return dis[n * m - 1];
    }
};

你可能感兴趣的:(#,图,算法,leetcode,c++)