【leetcode】1631. 最小体力消耗路径(path-with-minimum-effort)(二分+DFS)[中等]

23 篇文章 0 订阅
14 篇文章 0 订阅

链接

https://leetcode-cn.com/problems/path-with-minimum-effort/

耗时

解题:2 h 55 min
题解:38 min

题意

你准备参加一场远足活动。给你一个二维 rows x columns 的地图 heights ,其中 heights[row][col] 表示格子 (row, col) 的高度。一开始你在最左上角的格子 (0, 0) ,且你希望去最右下角的格子 (rows-1, columns-1) (注意下标从 0 开始编号)。你每次可以往 上,下,左,右 四个方向之一移动,你想要找到耗费 体力 最小的一条路径。

一条路径耗费的 体力值 是路径上相邻格子之间 高度差绝对值 的 最大值 决定的。

请你返回从左上角走到右下角的最小 体力消耗值 。

思路

建图,dfs都想到了,唯独没想到二分答案,看到提示二明白,,,

以每个格子为节点,每个格子到相邻格子的高度差绝对值为边权,建图。然后二分答案,二分判断条件为检查当前二分的答案——最小体力值是否可以在图中找到一条路使得这条路耗费的体力值小于最小体力值。是否可以找到这样的路径用dfs判断,因为bfs每次都要遍历所有节点才能知道是否可以找到,dfs则不需要,只有在最坏情况下才是遍历所有节点。

时间复杂度: O ( r o w s ∗ c o l u m n s ∗ l o g 1 0 6 ) O(rows*columns*log10^6) O(rowscolumnslog106)

AC代码

class Solution {
public:
    struct node {
        int to, cost;
    };
    vector<node> E[10100];
    void add_edge(int u, int v, int c) {
        E[u].push_back((node){v, c});
    }                                   
                                        
    vector<bool> vis;
    int rows = 1, columns = 1;
    int node_num = 1;
    int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    
    bool dfs(int u, int maxk) {
        if(u == node_num-1) {
            return true;
        }
        vis[u] = true;
        for(int i = 0; i < E[u].size(); ++i) {
            int to = E[u][i].to;
            if(vis[to]) continue;
            if(E[u][i].cost <= maxk) {
                bool flag = dfs(to, maxk);
                if(flag) return true;
            }
        }
        return false;
    }         
                                        
    bool check(int maxk) {
        vis.assign(10100, false);
        return dfs(0, maxk);
    }
                                        
    int minimumEffortPath(vector<vector<int>>& heights) {
        rows = heights.size();
        columns = heights[0].size();
        
        // build graph
        for(int i = 0; i < rows; ++i) {
            for(int j = 0; j < columns; ++j) {
                int sou = i*columns+j;
                for(int d = 0; d < 4; ++d) {
                    int x = i + dir[d][0];
                    int y = j + dir[d][1];
                    if((x >= 0 && x <= rows-1) && (y >= 0 && y <= columns-1)) {
                        int des = x*columns+y;
                        int cost = abs(heights[x][y]-heights[i][j]);
                        add_edge(sou, des, cost);
                    }
                }
            }
        }
        
        node_num = (rows-1)*columns+columns;
        
        // binary search
        int s = 0, t = 1000000;
        while(s < t) {
            int m = ((s+t)>>1);
            if(check(m)) t = m;
            else s = m+1;
        }
        return s;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值