1631.最小限の身体運動経路

あなたは遠足に参加するつもりです。格子の高さ表す2次元rows x columnsマップを作成しますグリッドの左上隅から開始し、グリッドの右下隅に移動します開始番号の添え字に注意してください)。毎回4つの方向のいずれかで上下左右に移動でき、エネルギー消費が最も少ないパスを見つけたいと考えています。heightsheights[row][col](row, col)(0, 0)(rows-1, columns-1)0

隣接する格子間のルートの物理パスコスト値の高さの差の絶対値最大値の決定。

左上隅から右下隅まで歩くための最小運動値を返してください。

例1:

ここに画像の説明を挿入します

输入:heights = [[1,2,2],[3,8,2],[5,3,5]]
输出:2
解释:路径 [1,3,5,3,5] 连续格子的差值绝对值最大为 2 。
这条路径比路径 [1,2,2,2,5] 更优,因为另一条路径差值最大值为 3 。

例2:

ここに画像の説明を挿入します

输入:heights = [[1,2,3],[3,8,4],[5,3,5]]
输出:1
解释:路径 [1,2,3,4,5] 的相邻格子差值绝对值最大为 1 ,比路径 [1,3,5,3,5] 更优。

例3:
ここに画像の説明を挿入します

输入:heights = [[1,2,1,1,1],[1,2,1,2,1],[1,2,1,2,1],[1,2,1,2,1],[1,1,1,2,1]]
输出:0
解释:上图所示路径不需要消耗任何体力。

促す:

  • rows == heights.length
  • columns == heights[i].length
  • 1 <= rows, columns <= 100
  • 1 <= heights[i][j] <= 10^6

回答

この質問では、左上隅から右下隅への最短パスが必要です。これは、これら2つのノードを含む最小全域木を見つけると見なすことができます。ここでのパスの長さは、パス全体の隣接するノードの高さの差の最小絶対値を指すことに注意してください。この質問でも、ユニオン検索+クラスカルアルゴリズムを使用して最小全域木を構築できます。

class DSU {
    
    
public:
    vector<int> parent;
    vector<int> rank;
    int n;
    int count;

    DSU(int n) : n(n), count(n) {
    
    
        parent.resize(n);
        rank.resize(n, 1);
        for(int i = 0; i < n; i++){
    
    
            parent[i] = i;
        }
    }

    int find(int i){
    
    
        if(i != parent[i]){
    
    
            int temp = find(parent[i]);
            parent[i] = temp;
        }
        return parent[i];
    }

    bool merge(int i, int j){
    
    
        int pi = find(i);
        int pj = find(j);
        if(pi == pj){
    
    
            return false;
        }
        else{
    
    
            if(rank[pi] > rank[pj]){
    
    
                swap(pi, pj);
            }
            rank[pj] += rank[pi];
            parent[pi] = pj;
            count -= 1;
        }
        return true;
    }

    bool connected(int i, int j){
    
    
        return find(i) == find(j);
    }
};

class Solution {
    
    
public:
    static constexpr int directions[4][2] = {
    
    {
    
    1, 0}, {
    
    -1, 0}, {
    
    0, 1}, {
    
    0, -1}};

    int minimumEffortPath(vector<vector<int>>& heights) {
    
    
        if(heights.size() == 0)
            return 0;
        int m = heights.size();
        int n = heights[0].size();
		// 构建图
        vector<vector<int>> edges;
        for(int i = 0; i < m; i++){
    
    
            for(int j = 0; j < n; j++){
    
    
                int id = i * n + j;
                // 从上往下
                if(i > 0){
    
    
                    int diff = abs(heights[i][j] - heights[i - 1][j]);
                    vector<int> temp{
    
    id - n, id, diff};
                    edges.emplace_back(temp);
                }
                // 从左往右
                if(j > 0){
    
    
                    int diff = abs(heights[i][j] - heights[i][j - 1]);
                    vector<int> temp{
    
    id - 1, id, diff};
                    edges.emplace_back(temp);
                }
            }
        }
        // Kruskal, 按边长排序
        sort(edges.begin(), edges.end(), [](const auto& e1, const auto& e2){
    
    
            return e1[2] < e2[2];
        });

        // 并查集构建最小生成树
        DSU dsu(m * n);
        int result = 0;
        for(const auto& e : edges){
    
    
            int u = e[0];
            int v = e[1];
            int distance = e[2];
            dsu.merge(u, v);
            // 说明左上到右下的路径构建完成
            if(dsu.connected(0, m * n - 1)){
    
    
                result = distance;
                break;
            }
        }
        return result;
    }
};

優先キューを使用して最適化されたDijskraアルゴリズム:

class Solution {
    
    
private:
    static constexpr int dirs[4][2] = {
    
    {
    
    -1, 0}, {
    
    1, 0}, {
    
    0, -1}, {
    
    0, 1}};
    
public:
    int minimumEffortPath(vector<vector<int>>& heights) {
    
    
        int m = heights.size();
        int n = heights[0].size();
        
        auto tupleCmp = [](const auto& e1, const auto& e2) {
    
    
            auto&& [x1, y1, d1] = e1;
            auto&& [x2, y2, d2] = e2;
            return d1 > d2;
        };
        priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, decltype(tupleCmp)> q(tupleCmp);
        q.emplace(0, 0, 0);

        vector<int> dist(m * n, INT_MAX);
        dist[0] = 0;
        vector<int> seen(m * n);

        while (!q.empty()) {
    
    
            auto [x, y, d] = q.top();
            q.pop();
            int id = x * n + y;
            if (seen[id]) {
    
    
                continue;
            }
            if (x == m - 1 && y == n - 1) {
    
    
                break;
            }
            seen[id] = 1;
            for (int i = 0; i < 4; ++i) {
    
    
                int nx = x + dirs[i][0];
                int ny = y + dirs[i][1];
                if (nx >= 0 && nx < m && ny >= 0 && ny < n && max(d, abs(heights[x][y] - heights[nx][ny])) < dist[nx * n + ny]) {
    
    
                    dist[nx * n + ny] = max(d, abs(heights[x][y] - heights[nx][ny]));
                    q.emplace(nx, ny, dist[nx * n + ny]);
                }
            }
        }
        
        return dist[m * n - 1];
    }
};

// 作者:LeetCode-Solution
// 链接:https://leetcode-cn.com/problems/path-with-minimum-effort/solution/zui-xiao-ti-li-xiao-hao-lu-jing-by-leetc-3q2j/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

おすすめ

転載: blog.csdn.net/WhiteGray/article/details/113370213