leetcode刷题:每日一题-1631. 最小体力消耗路径

这篇博客介绍了如何使用迪杰斯特拉算法和并查集来解决寻找网格中从左上角到右下角的最小体力消耗路径问题。迪杰斯特拉算法通过优先队列不断更新节点的最小消耗,而并查集则用于快速判断不同节点是否联通。两种方法分别进行了详细解释,并提供了实现代码示例。
摘要由CSDN通过智能技术生成

在这里插入图片描述在这里插入图片描述
思路:迪杰斯特拉最短路径应用到该题,初步思想:将每个空格看作每个节点,相邻的节点之间存在边,边的权值为相邻值的高度差,求左上角到右下角的最小体力消耗,即为类似求原点到终点的路径。(会超越时间限制)

官方思路:(迪杰斯特拉:)

利用优先队列存储节点坐标(x,y)和当前时刻原点到该点的最小体力消耗值(d),优先队列以d值降序排序,(priority_queue每次都是从队尾取元素的,所以使用top()返回的是排序后的最后一个元素。),然后用top取出下一个节点,对该节点的所有邻居节点进行更新。

class Solution {
private:
    int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
public:
    int minimumEffortPath(vector<vector<int>>& heights) {
        if (heights.empty())
            return -1;
        //类迪杰斯特拉算法 更新起点到每个点的最小体力消耗          
        int rows = heights.size();          //行数
        int colums = heights[0].size();     //列数
        int numVertexes = rows*colums;

        vector<int> MinConsume(numVertexes,INT_MAX);
        vector<int> Flag(numVertexes,0);

        auto cmp = [](auto &e1, auto &e2)    //priority_queue每次都是从队尾取元素的,所以使用top()返回的是排序后的最后一个元素。
        {
            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(cmp)> q(cmp);
        q.emplace(0,0,0);
        MinConsume[0] = 0;

        while(!q.empty())
        {
            auto [x,y,d] = q.top();
            q.pop();
            int id = x*colums+y;
            
            if ( Flag[id] == 1 )
                continue;

            if ( x == rows-1 && y == colums-1 )
                break;

            Flag[id] = 1;
            for(int i=0;i<4;i++)
            {
                int xn = x + dirs[i][0];
                int yn = y + dirs[i][1];
                int idn = xn*colums+yn;
                if (xn>=0 && xn<rows && yn>=0 && yn<colums && max(d,abs(heights[x][y]-heights[xn][yn]))<MinConsume[idn] )
                {
                    MinConsume[idn] = max(d,abs(heights[x][y]-heights[xn][yn]));
                    q.emplace(xn,yn,MinConsume[idn]);
                }
            }
        }
        return MinConsume[rows*colums-1];
    }
       
};

并查集方法:
在这里插入图片描述

class UnionFind{
public:
    vector<int> parent;
    vector<int> size;
    int n;
    //连通分量数目
    int setCount;

public:
    UnionFind(int _n):n(_n), setCount(_n), parent(_n), size(_n,1) {
        iota(parent.begin(), parent.end(), 0);     //iota函数将parent容器中从头到尾进行赋值,第一个元素为0,随后自增
    }

    int findset(int x){
        return x == parent[x] ? x : parent[x] = findset(parent[x]);
    }

    bool unite( int x, int y ){
        int fx = findset( x );
        int fy = findset( y );

        if ( fx == fy )
            return false;
        if ( size[fx] > size[fy] ){
            int temp = fx;
            fx = fy;
            fy = temp;
        }
        parent[fx] = fy;
        size[fy] += size[fx];
        setCount--;
        return true;
    }

    bool isconnect( int x, int y ){
        int fx = findset( x );
        int fy = findset( y );
        return fx == fy;
    }
};

class Solution {
private:
    int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
public:
    int minimumEffortPath(vector<vector<int>>& heights) {
        if (heights.empty())
            return -1;
        int rows = heights.size();          //行数
        int colums = heights[0].size();     //列数
        int numVertexes = rows*colums;

        //并查集方法
        vector<tuple<int,int,int>> edges;
        //初始化所有的边
        for(int i=0;i<rows;i++){
            for(int j=0;j<colums;j++){
                int id = i*colums+j;
                if ( i > 0){
                    edges.emplace_back( id-colums, id, abs(heights[i-1][j]-heights[i][j]));
                }
                if ( j > 0){
                    edges.emplace_back( id-1, id, abs(heights[i][j-1]-heights[i][j]));
                }
            }
        }
        //对所有的边进行排序
        sort( edges.begin(), edges.end(), [](const auto &e1,const auto &e2){
            auto && [x1,y1,d1] = e1;
            auto && [x2,y2,d2] = e2;
            return d1 < d2;
        } );

        UnionFind uf(numVertexes);
        int result = 0;
        //并查集主体函数
        for( const auto [x,y,d]:edges ){
            uf.unite( x, y );
            if ( uf.isconnect( 0, numVertexes-1 ) ){
                result = d;
                break;
            } 
        }
        return result;
    }

并查集通用类:UnionFind

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值