/*
bfs队列
[x,x,x | x+1,x+1]
1 两段性
2 单调性
1 初始 [0] 满足
2 假设 [x,x,x | x+1,x+1]
取队头x 并将j == ne[x] == x+1 加入队列 依然保持了两段性和单调性
[x,x,x | x+1,x+1,(x+1)]
x → j
1
类比 堆优化 dijkstra
起点→queue
while(q.size())
{
t ← 小根堆顶
for j in ne[t]:
更新
}
边权都==1时 上面那个队列相当于堆优化的队列
所有点都只会入队一次 所以入队过 点的值就不会被改变
证明:
反证
假设当前所有出队的元素的最小值已经确定了
假设当前队头d[x]!=最小值
那么x会被当前队列中的后面的某个点通过某条路经更新 且d[x]被更新后会严格减小
o←o←o 这条路径上的点要么是在队列中x之后,要么还没进队列
↓ ↑ 且这条路径每条边权==1 则这条路径距离=d[x]+(i*1),i>=0 >= d[x]
[x,x,x | x+1,x+1,(x+1)]
⭐则有 x+(i*1),i>=0 >= x 与 d[x]被更新后会严格减小 矛盾
所以队头出来的x 就一定是最小值
所有点都只会入队一次 所以入队过 点的值就不会被改变
*/
/*
理解一个东西
那就是BFS是逐层往外扩散的
那么它本身就带有最短路特性
当我们把1都加入队列 与这一块1最近的点j必然会被先计算距离
所以可以直接当作最短路而不用考虑其他1到j的可能的最短路距离
连续数字读取用char
*/
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N=1010;
int m,n;
char g[N][N];
int d[N][N];
bool st[N][N];
queue<PII> q;
int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
void bfs()
{
while(q.size())
{
auto t = q.front();
q.pop();
int x=t.first,y=t.second;
for(int i=0;i<4;i++)
{
int nx=x+dirs[i][0],ny=y+dirs[i][1];
if(nx<0 || nx>=m || ny<0 || ny>=n || st[nx][ny] || g[nx][ny]=='1') continue;
d[nx][ny] = d[x][y]+1;
q.push({nx,ny});
st[nx][ny] = true;
}
}
}
int main()
{
cin >> m >> n;
for(int i=0;i<m;i++)
{
cin >> g[i];
for(int j=0;j<n;j++)
{
if(g[i][j]=='1') q.push({i,j});
}
}
bfs();
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cout << d[i][j] << ' ';
}
cout << endl;
}
return 0;
}