链接
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(rows∗columns∗log106)
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;
}
};