力扣1631. 最小体力消耗路径

力扣

[二分广搜或并查集或最短路]最小体力消耗路径

1)二分限定边权的值x

每次搜索,只有小于等于x的值才可以被允许。

class Solution {
public:
    vector<vector<int>> g;
    int n,m;
    int minimumEffortPath(vector<vector<int>>& heights) {
        if(!heights.size() || !heights[0].size()) return 0;

        n = heights.size();
        m = heights[0].size();
        g = heights;

        int l = 0 ,r = 1e6;
        while(l < r){
            int mid = l + r >> 1;
            if(ck(mid)) r = mid;
            else l = mid + 1;
        }
        return l;
    }

    bool ck(int x){
        queue<pair<int,int>> q;
        int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
        q.push({0,0});
        //可以用一手状态压缩,位置为(i, j)的格子对应的编号为 i * n + j
        vector<vector<int>> st(n,vector<int>(m,0));
        st[0][0] = 1;
        while(q.size()){
            int xx = q.front().first;
            int yy  =q.front().second;
            if(xx == n-1 && yy == m-1) return true;
            // cout<<xx<<" "<<yy<<endl;
            q.pop();
            for(int i=0;i<4;i++){
                int nx = xx + dx[i];
                int ny = yy + dy[i];
                if(nx < 0 || nx >= n || ny < 0 || ny >= m || st[nx][ny]) continue;
                if(abs(g[xx][yy] - g[nx][ny]) > x) continue;
                st[nx][ny] = 1;
                q.push({nx,ny});
            }
        }
        return false;
    }
};
2)并查集

将n*m 个节点放入并查集中,将图中的所有边按照权值从小到大进行排序,并依次加入并查集中,当某次加入一条边时,这两个点联通了,此时的x就是答案。(有点类似最小生成树?)

(把vector放在方法()里TLE了好多次。。)

struct edge{
    int u,v,w;
    bool operator<(const edge &t)const{
        return w < t.w;
    }
};
class Solution {
public:
    vector<int> f;
    int minimumEffortPath(vector<vector<int>>& g) {
        int n = g.size();
        int m = g[0].size();
        
        vector<edge> e;
        vector<int> ff(n*m);
        for(int i=0;i<n*m;i++) ff[i] = i;
        f = ff;
        
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                int id = i * m + j;
                if(i) e.push_back({id-m,id,abs(g[i][j] - g[i-1][j])});
                if(j) e.push_back({id-1,id,abs(g[i][j] - g[i][j-1])});
            }
        }
        sort(e.begin(),e.end());
        
        int res = 0;
        for(int i=0;i<e.size();i++){
            int u = e[i].u,v = e[i].v,w= e[i].w;
            u = finds(u);
            v = finds(v);
            // cout<<u<<" "<<v<<endl;
            if(u != v){
                f[v] = u;
            }
            if(finds(0) == finds(n*m-1)){
                res = w;
                break;
            }
        }
        return res;
    }	

    int finds(int x){
        return x == f[x] ? x : f[x] = finds(f[x]);
    }
};
3)最短路变形

定义最短路径为所经过的所有边权的最大值,而不是求和。
用堆优化dijkstra求最短路

https://en.wikipedia.org/wiki/A*_search_algorithm
https://en.wikipedia.org/wiki/Consistent_heuristic
https://en.wikipedia.org/wiki/Admissible_heuristic
参考学习 Dijkstra 算法的本质
struct node{
    int x,y,w;
    bool operator<(const node &t)const{
        return w > t.w;
    }
};

class Solution {
public:
    const int inf = 1e8;
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    int minimumEffortPath(vector<vector<int>>& g) {
        int n = g.size();
        int m = g[0].size();
        priority_queue<node> q;
        q.push({0,0,0});
        int ed = n * m - 1;

        vector<int> dis(n*m,inf),st(n*m,0);
        dis[0] = 0;

        while(q.size()){
            auto t = q.top();
            int x = t.x,y = t.y,w = t.w;
            q.pop();
            int id = x * m + y;
            if(st[id]) continue;
            st[id] = 1;
            if(x == n-1 && y == m-1){
                break;
            }

            for(int i=0;i<4;i++){
                int nx = x + dx[i];
                int ny = y + dy[i];
                if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
                if(max(w,abs(g[x][y] - g[nx][ny])) >= dis[ed]) continue;
                dis[nx * m + ny] = max(w,abs(g[x][y] - g[nx][ny]));
                q.push({nx,ny,dis[nx * m + ny]});
            }

        }
        return dis[ed];
    }
};
posted @   Isaac233  阅读(40)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示