1.题目
题目链接:点这儿!
2.解决方法
题目中提到曼哈顿距离,实际上就是矩阵中求最短路这种题的点到点的距离;求最短路,很自然的想到BFS(毕竟如dijkstra、spfa 等最短路算法的实现本质上很像BFS)求最短路,可以从起点到终点,也可以从终点到起点(比如记录最短路径经过的点,最好这样做)
现在的问题是,看起来起点有很多个,终点也有很多个,如果从每个非1的点开始,BFS求最近的1(有点像flood fill?)这样粗略分析一下,复杂度O(n^4/4)!太恐怖了!不如这样考虑:利用BFS队列中序列具有两段性(即序列中一定是由前面的一段x和后面的一段x+1构成的)推导出同时具有单调性,这样,先将所有的1点加入队列(此所谓多源)开始BFS,逐层向外扩展(想象一下向水中撒一把石子水面的样子)记录答案的dist每个点只会被更新一次;最终得到答案。
3.代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int MAXN=1010;
int n,m;
char s[MAXN][MAXN];
int dist[MAXN][MAXN];
int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
//多源bfs:相比于单源bfs求从单个起点到终点的最短路径,bfs活结点队列中开始只有一个起点,多源bfs的活结点队列一开始有多个起点
//本题要求的是,所有点到最近的1的最短路径,那么可以以每一个1为起点进行多源bfs,层层扩展,求得所有点到最近的1的距离
void bfs()
{
queue<PII> q;
memset(dist,-1,sizeof(dist));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='1'){
dist[i][j]=0;
q.push({i,j});
}
while(!q.empty()){
PII t=q.front();
q.pop();
for(int i=0;i<4;i++){
int nx=t.x+dx[i],ny=t.y+dy[i];
if(nx<0||nx>=n||ny<0||ny>=m) continue;
if(dist[nx][ny]==-1){
dist[nx][ny]=dist[t.x][t.y]+1;
q.push({nx,ny});
}
}
}
}
int main(void)
{
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>s[i];
bfs();
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
cout<<dist[i][j]<<' ';
cout<<endl;
}
return 0;
}