【问题标题】:How does this Dijkstra code return minimum value (and not maximum)?这个 Dijkstra 代码如何返回最小值(而不是最大值)?
【发布时间】:2021-11-29 07:47:08
【问题描述】:

我正在 LeetCode.com 上解决这个名为 Path With Minimum Effort 的问题:

给定高度,一个大小为行 x 列的二维数组,其中 heights[row][col] 表示单元格 (row, col) 的高度。目标是从左上角到右下角。您可以向上、向下、向左或向右移动,并且您希望找到一条需要最少努力的路线。路线的努力是路线的两个连续单元格之间的最大绝对高度差。返回从左上角单元格移动到右下角单元格所需的最小努力。例如,如果heights = [[1,2,2],[3,8,2],[5,3,5]],则答案是2(绿色)。

我的代码是:

class Solution {
public:
    vector<pair<int,int>> getNeighbors(vector<vector<int>>& h, int r, int c) {
        vector<pair<int,int>> n;
        if(r+1<h.size()) n.push_back({r+1,c});
        if(c+1<h[0].size()) n.push_back({r,c+1});
        if(r-1>=0) n.push_back({r-1,c});
        if(c-1>=0) n.push_back({r,c-1});
        return n;
    }
    
    int minimumEffortPath(vector<vector<int>>& heights) {
        int rows=heights.size(), cols=heights[0].size();
        
        using arr=array<int, 3>;
        priority_queue<arr, vector<arr>, greater<arr>> pq;
        vector<vector<int>> dist(rows, vector<int>(cols, INT_MAX));
        pq.push({0,0,0});    //r,c,weight
        dist[0][0]=0;
        
        //Dijkstra
        while(pq.size()) {
            auto [r,c,wt]=pq.top();
            pq.pop();
            
            if(wt>dist[r][c]) continue;
            
            vector<pair<int,int>> neighbors=getNeighbors(heights, r, c);
            for(auto n: neighbors) {
                int u=n.first, v=n.second;
                int curr_cost=abs(heights[u][v]-heights[r][c]);
                if(dist[u][v]>max(curr_cost,wt)) {
                    dist[u][v]=max(curr_cost,wt);
                    pq.push({u,v,dist[u][v]});
                }
            }
        }
        
        return dist[rows-1][cols-1];
    }
};

这被接受了,但我有两个问题:

一个。既然我们更新dist[u][v],如果它大于max(curr_cost,wt),它如何保证最终我们返回所需的最小 努力?也就是说,我们为什么不最终回报上面红色的努力?

b.一些解决方案,例如this one,当我们第一次到达右下角时短路并立即返回(即if(r==rows-1 and c==cols-1) return wt;) - 这是如何工作的?当我们以后重新访问右下角节点时,我们不能得到更短的dist 吗?

【问题讨论】:

  • 所以你写的代码你看不懂?
  • @ChrisMM,有很多 WA 用于找出 dist[u][v]&gt;max(curr_cost,wt) 条件,是的。
  • @Someone 哇,这就是我所说的高效学习。建议:最好用一些good books 来浪费你的时间。
  • 首先从红色路径中获得 3,因为红色路径将首先从队列中出来(距离最后一次移动的距离为 1)。所以从最后 2 到 5 的移动将设置dist[2][2] = 3。但是,当算法将探索绿色路径上 (row=2,col=1) 处的 3 时,您将拥有 dist[2][2] = 3curr_cost=2wt=2。所以dist[2][2] &gt; max(curr_cost, wt)dist[2][2] 减少到 2。所以是的,最短路径是具有 最小 最大绝对差异的路径。
  • @user3386109,完美!这回答了我的问题。如果您将其转换为答案,请告诉我。我会非常乐意接受它。再次感谢! :)

标签: c++ algorithm graph dijkstra graph-traversal


【解决方案1】:

问题陈述要求我们找到最小“努力”的路径。
而“努力”被定义为路径上相邻单元之间的最大高度差

表达式max(curr_cost, wt) 负责问题陈述的最大部分。从一个单元格移动到另一个单元格时,到新单元格的距离或者与到旧单元格的距离相同,或者是高度差,以较大者为准。因此max(difference_in_heights, distance_to_old_cell)

并且 Dijkstra 的算法处理了问题陈述的 minimum 部分,我们不是使用与起始节点的距离,而是使用从起始节点获取所需的“努力”到任何给定的节点。 Dijkstra 试图最小化距离,因此它最小化了努力。

Dijkstra 有两个密切相关的概念:visitedexplored。当任何传入边用于到达该节点时,该节点被访问。当一个节点的出边被用来访问它的邻居时,它被探索。 Dijkstra 的关键设计特点是,在一个节点被探索 之后,对该节点的额外访问 永远不会提高到该节点的距离。这就是优先队列的原因。优先级队列保证被探索的节点在所有未探索节点中距离最小。

在示例网格中,红色路径将在绿色路径之前探索,因为红色路径在最后一步之前的努力为 1,而绿色路径的努力为 2。因此红色路径将距离设置为右下角单元格为 3,即dist[2][2] = 3

但是当探索绿色路径时,我们到达 3 的 row=2, col=1,我们有

  • dist[2][2] = 3
  • curr_cost=2
  • 重量=2

所以dist[2][2] &gt; max(curr_cost, wt)dist[2][2] 减少到 2。

问题的答案:

一个。红色路径确实将右下角的单元格临时设置为距离 3。但是红色路径的结果被丢弃,取而代之的是绿色路径的结果。这是 Dijkstra 算法寻找最小值的自然结果。

b.当右下角的节点准备好探索时,即它位于优先级队列的头部,那么它就有了有史以来最好的距离,所以算法可以在那个点停止。这也是 Dijkstra 算法的自然结果。优先级队列保证在一个节点被探索之后,以后对该节点的访问不会减少它的距离。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 2019-06-24
    相关资源
    最近更新 更多