https://leetcode-cn.com/problems/path-with-minimum-effort/
思路一:二分,由于格子的取值范围为
[
1
,
1
0
6
]
[1,10^6]
[1,106],所以最终结果的取值范围一定
[
0
,
1
0
6
]
[0,10^6]
[0,106]之内,我们可以二分最终结果的值,然后看在这个限制条件下能否从左上角走到右下角,再依据结果缩小二分范围。
class Solution {
public:
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
bool bfs(vector<vector<int>>& heights,int inf)
{
using pr=pair<int,int>;
queue<pr> q;
int n=heights.size(),m=heights[0].size();
vector<vector<bool>> vis(n,vector<bool>(m));
q.push(pr(0,0));
vis[0][0]=1;
while(!q.empty())
{
pr fon=q.front();
if(fon.first==n-1&&fon.second==m-1)
return 1;
q.pop();
for(int i=0;i<4;i++)
{
int dx=fon.first+dir[i][0];
int dy=fon.second+dir[i][1];
if(dx>=0&&dx<n&&dy>=0&&dy<m&&!vis[dx][dy]&&abs(heights[dx][dy]-heights[fon.first][fon.second])<=inf)
q.push(pr(dx,dy)),vis[dx][dy]=1;
}
}
return 0;
}
int minimumEffortPath(vector<vector<int>>& heights) {
int l=0,r=1e6,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(bfs(heights,mid))
r=mid-1;
else
l=mid+1;
}
return l;
}
};
思路二:并查集,类似于最小生成树的做法,我们可以假设每个点都和周围相邻点有一条边,权值即为二者的绝对值,然后对边集进行排序,从小到大做并操作,直到左上角和右下角联通。
class Edge
{
public:
int x,y,v;
Edge(int x,int y,int v):x(x),y(y),v(v){}
bool operator <(const Edge &e)const
{
return v<e.v;
}
};
class Solution {
public:
vector<int> f;
int father(int x)
{
return f[x]==x?x:f[x]=father(f[x]);
}
void uni(int x,int y)
{
int fx=father(x);
int fy=father(y);
if(fx!=fy)
f[fx]=fy;
}
int minimumEffortPath(vector<vector<int>>& heights) {
vector<Edge> edges;
int n=heights.size(),m=heights[0].size(),nm=n*m;
f.resize(nm);
for(int i=1;i<nm;i++)
f[i]=i;
for(int i=0;i<n;i++)
{
int idx_base=i*m;
for(int j=0;j<m;j++)
{
if(j!=m-1)
edges.push_back(Edge(idx_base+j,idx_base+j+1,abs(heights[i][j]-heights[i][j+1])));
if(i!=n-1)
edges.push_back(Edge(idx_base+j,idx_base+j+m,abs(heights[i][j]-heights[i+1][j])));
}
}
sort(edges.begin(),edges.end());
for(Edge& e : edges)
{
uni(e.x,e.y);
if(father(0)==father(nm-1))
return e.v;
}
return 0;
}
};
思路三:类似于 d i j k s t r a dijkstra dijkstra的的思想,以左上角为起点跑最短路算法,只不过对距离的定义发生了变化(传统是累加,这里是取绝对值的最大值)。由于该图中边是隐式定义的,所以其实就是堆+ b f s bfs bfs。
class node
{
public:
int x,y,dis;
node(){}
node(int x,int y,int d):x(x),y(y),dis(d){}
node(const node& a):x(a.x),y(a.y),dis(a.dis){}
bool operator <(const node& b)const
{
return dis>b.dis;
}
};
class Solution {
public:
int minimumEffortPath(vector<vector<int>>& heights) {
const int inf=0x3f3f3f3f;
int n=heights.size(),m=heights[0].size();
int dir[4][2]={{0,-1},{0,1},{1,0},{-1,0}};
vector<vector<bool>> vis(n,vector<bool>(m));
priority_queue<node> q;
q.push(node(0,0,0));
while(!q.empty())
{
node fon=q.top();
q.pop();
if(fon.x==n-1&&fon.y==m-1)
return fon.dis;
else if(vis[fon.x][fon.y])
continue;
vis[fon.x][fon.y]=1;
for(int i=0;i<4;i++)
{
int dx=fon.x+dir[i][0];
int dy=fon.y+dir[i][1];
if(dx>=0&&dx<n&&dy>=0&&dy<m&&!vis[dx][dy])
q.push(node(dx,dy,max(fon.dis,abs(heights[dx][dy]-heights[fon.x][fon.y]))));
}
}
return 0;
}
};