暴力BFS or 多源最短路 or DP: Leetcode 1162 地图分析
问题:
思路:
暴力BFS:
对所有海洋坐标点进行BFS,求出它们到最近陆地的曼哈顿距离,再从中选取最大值
对每个(x,y)需向四个方向进行搜索,
即(x,y+1),(x,y-1),(x+1,y),(x-1,y)
需记录遍历到每个坐标点时已走过的距离,因此将坐标点定义为结构体,结构体成员为坐标以及已走过的距离
由于求的是到最近陆地的曼哈顿距离,因此遍历到陆地BFS函数即可返回距离,无需和经典BFS一样等到队列为空
多源最短路:
问题是求所有海洋点集到陆地点集的最短路,是一个多源最短路问题,多源最短路问题可以转化为单源最短路问题,即建立一个超级源点S,它与源点集中的所有点都有边,但权值为0,这样求源点集到目标点集的最短路就变成了求超级源点 S 到它们的最短路。
源点集和目标点集的选择:
源点集为陆地,目标点集为海洋,理由如下:
若源点集为海洋,目标点集为陆地,则目标点集中的点的距离信息为海洋点集中的点到该点的最短路径,举个例子,若海洋1到陆地1的距离为4,海洋2到陆地1的距离为5,则陆地1的距离信息为4,若离海洋1,2最近的陆地均为陆地1,则会发生结果错误,结果应为5而不是4
若源点集为陆地,目标点集为海洋,则目标点集中的点的距离信息为陆地点集中的点到该点的最短路径,即记录了每个海洋节点的最近陆地节点信息,在其中取最大值即可
建立距离矩阵distance, distance[i ] [j ] 表示超级源点到点(i,j)的最短路径距离,初始值为:对于源点集,距离均为0,对于目标点集,距离为无穷大
将源点集中的点全部入队列,进行BFS,对每个节点,向四个方向进行遍历,若当前点的距离值+1小于遍历到的点的距离值,则更新遍历到的点的距离值,并将其入队列
当队列为空时多源BFS执行完毕
遍历目标点集中每个点的距离,取最大值返回
将上述BFS过程看成结点状态更新的过程,在上述过程中,除开最开始就入队的源点集,之后入队的点为状态可更新的点(状态更新后,该状态更新造成的结果可能进一步传播,因此必须入队),状态不能更新的点无须入队。因此是不需要visit标记数组的,在队列为空遍历完成时,所有结点的状态均为最佳
DP:
用f(x,y)表示(x,y)到最近的陆地点的曼哈顿距离
离(x,y)最近的点若在其上方,则需向上走一步,即
f(x,y)=f(x,y-1)+1
若在其左方,则需向左一步
f(x,y)=f(x-1,y)+1
若在其下方,需向下一步
f(x,y)=f(x,y+1)+1
若在其右方,需向右一步
f(x,y)=f(x+1,y)+1
f(x,y)的初始值为:陆地点为0,海洋点为INF
对左和上方的情况进行一轮DP,DP对表的填充从左上方到右下方
对右和下方的情况进行一轮DP,DP对表的填充从右下方到左上方
找到海洋点中f(x,y)的最大值,即为所求
代码:
暴力BFS:
class Solution {
public:
int dx[4]={ 0,0,1,-1 };
int dy[4]={ 1,-1,0,0 };
int n,m;
int visited[101][101];
vector<vector<int>> matrix;
struct point
{
int x,y;
int step;
};
int BFS( int x,int y )
{
int i;
memset( visited,0,sizeof(visited) );
queue<point> q;
q.push( {x,y,0} );
visited[x][y]=1;
while( q.size()!=0 )
{
auto temp=q.front();
q.pop();
for( i=0;i<4;i++ )
{
int nx=temp.x+dx[i];
int ny=temp.y+dy[i];
if( nx<0 || nx>=m || ny<0 || ny>=n )
continue;
if( visited[nx][ny]==0 )
{
visited[nx][ny]=1;
q.push( {nx,ny,temp.step+1} );
if( matrix[nx][ny]==1 )
return temp.step+1;
}
}
}
return -1;
}
int maxDistance(vector<vector<int>>& grid) {
int ans=-1;
int i,j;
n=grid.size();
m=grid[0].size();
matrix=grid;
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
if( grid[i][j]==0 )
ans=max( ans,BFS( i,j ) );
return ans;
}
};
多源最短路:
class Solution {
public:
int dx[4]={ 0,0,1,-1 };
int dy[4]={ 1,-1,0,0 };
int n,m;
int distance[101][101];
vector<vector<int>> matrix;
struct point
{
int x,y;
};
int maxDistance(vector<vector<int>>& grid) {
int ans=-1;
int i,j;
n=grid.size();
m=grid[0].size();
memset( distance,1e+06,sizeof(distance) );
queue<point> q;
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
if( grid[i][j]==1 )
{
distance[i][j]=0;
q.push( {i,j} );
}
while( q.size()!=0 )
{
auto temp=q.front();
q.pop();
for( i=0;i<4;i++ )
{
int nx=temp.x+dx[i];
int ny=temp.y+dy[i];
if( nx<0 || nx>=n || ny<0 || ny>=m )
continue;
if( distance[nx][ny]>distance[ temp.x ][ temp.y ]+1 )
{
distance[nx][ny]=distance[ temp.x ][ temp.y ]+1;
q.push( {nx,ny} );
}
}
}
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
if( grid[i][j]==0 )
ans=max( ans,distance[i][j] );
return ans>=1e+05? -1:ans;
}
};
DP:
class Solution {
public:
int maxDistance(vector<vector<int>>& grid) {
int n=grid.size();
int m=grid[0].size();
int f[101][101];
int i,j;
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
{
if( grid[i][j]==1 )
f[i][j]=0;
else
f[i][j]=1e+06;
}
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
{
if( grid[i][j]==0 )
{
if( i-1>=0 )
f[i][j]=min( f[i-1][j]+1,f[i][j] );
if( j-1>=0 )
f[i][j]=min( f[i][j-1]+1,f[i][j] );
}
}
for( i=n-1;i>=0;i-- )
for( j=m-1;j>=0;j-- )
{
if( grid[i][j]==0 )
{
if( i+1<n )
f[i][j]=min( f[i+1][j]+1,f[i][j] );
if( j+1<m )
f[i][j]=min( f[i][j+1]+1,f[i][j] );
}
}
int ans=-1;
for( i=0;i<n;i++ )
for( j=0;j<m;j++ )
{
if( grid[i][j]==0 )
ans=max(ans,f[i][j]);
}
return ans>=1e+05? -1:ans;
}
};