给定一个N行M列的01矩阵A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
dist(A[i][j],A[k][l])=|i−k|+|j−l|
输出一个N行M列的整数矩阵B,其中:
B[i][j]=min1≤x≤N,1≤y≤M,A[x][y]=1dist(A[i][j],A[x][y])
输入格式
第一行两个整数n,m。
接下来一个N行M列的01矩阵,数字之间没有空格。
输出格式
一个N行M列的矩阵B,相邻两个整数之间用一个空格隔开。
数据范围
1≤N,M≤1000
输入样例:
3 4
0001
0011
0110
输出样例:
3 2 1 0
2 1 0 0
1 0 0 1
代码
#include <iostream>
#include<cstring>
#include<queue>
using namespace std;
int n,m,dx[5]={-1,0,1,0},dy[5]={0,1,0,-1};//上右下左四个点的偏移量
char A[1005][1005];
int B[1005][1005];
void bfs(){
memset(B,-1,sizeof B);//初始化B矩阵为-1,代表所有点均未被访问
queue<pair<int,int> > q;//定义队列实现广搜
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(A[i][j]=='1'){//矩阵A中所有为1的点为起点
q.push({i,j});//将其下标压入队列
该点离某起点的最短距离为0(自己就是起点之一)
B[i][j]=0;//,标志该点已被访问
}
}
}//队列中的点离某起点(A矩阵中值为1的点)的最短距离是单调递增
while(q.size()){
auto f = q.front();//取出队头
q.pop();//弹出队头
int x = f.first;//获取队头横坐标
int y = f.second;//获取队头纵坐标
for(int i=0;i<4;i++){//遍历队头直接连接的四个方向的点
int a = x + dx[i];//获得其坐标
int b = y + dy[i];
if(a>=0&&a<n&&b>=0&&b<m&&B[a][b]==-1){//该点未越界且未访问过
//该点离某个起点的最短距离等于队头元素离起点的最短距离+1
B[a][b]=B[x][y]+1;
q.push({a,b});//将该点下标压入队列
}
}
}
}
int main()
{
cin >> n>> m;
for(int i=0;i<n;i++)//因为是01字符串所以可以一次输1行
cin>>A[i];
//广搜:多源点最短路径问题,也可以把他看作单源点最短路径问题,引入一个虚拟结点
bfs();//虚拟结点到各个起点的距离为0
for(int i=0;i<n;i++){//输出其结果
for(int j=0;j<m;j++){
cout<<B[i][j]<<" ";
}
cout<<endl;
}
return 0;
}