Problem:
Score : 300 points

Problem Statement

You are given a grid of squares with H horizontal rows and W vertical columns, where each square is painted white or black.
HW characters from A_{11} to A_{HW} represent the colors of the squares.
A_{ij} is # if the square at the i-th row from the top and the j-th column from the left is black, and A_{ij} is . if that square is white.

We will repeatedly perform the following operation until all the squares are black:

Every white square that shares a side with a black square, becomes black.

Find the number of operations that will be performed.
The initial grid has at least one black square.

Constraints

1 \leq H,W \leq 1000

A_{ij} is # or ..

The given grid has at least one black square.

Input

Input is given from Standard Input in the following format:

H W
A_{11}A_{12}...A_{1W}
:
A_{H1}A_{H2}...A_{HW}

Output

Print the number of operations that will be performed.

Sample Input 1

3 3
...
.#.
...

Sample Output 1

2

After one operation, all but the corners of the grid will be black. After one more operation, all the squares will be black.

Sample Input 2

6 6
..#..#
......
#..#..
......
.#....
....#.

Sample Output 2

3

Solution in Rust (1.42.0) (judge verdict: Accepted)

#![allow(non_snake_case)]
#![allow(unused_imports)]
use ascii::AsciiChar;
use ascii::AsciiStr;
use itertools::Itertools as _;
use permutohedron::LexicalPermutation as _;
use petgraph::algo::dijkstra;
use petgraph::algo::min_spanning_tree;
use petgraph::data::FromElements;
use petgraph::graph::NodeIndex;
use petgraph::graph::UnGraph;
use petgraph::unionfind::UnionFind;
use proconio::fastout;
use proconio::input;
use proconio::marker::Chars;
use proconio::marker::Usize1;
use std::cmp::max;
use std::cmp::min;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use superslice::Ext as _;

#[fastout]
fn main() {
    input! {
        H: usize,
        W: usize,
        Fieldsz: [Chars; H],
    }

    // 初期の'#'から一番「遠い」点との距離は? という問題
    // 幅優先みたいにやりたいけど、スタート地点が複数あるのが困る
    // いや困らないわ。制約的に間に合いそう。
    // ダイクストラ感がある

    let mx: i64 = (H * W + 1) as i64;

    // 最も近い'#'からの距離
    let mut distsz: Vec<Vec<i64>> = vec![vec![mx; W]; H];

    // まず、'#'を抽出してくる
    let mut heap: BinaryHeap<Reverse<(i64, isize, isize)>> = BinaryHeap::new();

    for h in 0..H {
        for w in 0..W {
            if Fieldsz[h][w] == '#' {
                distsz[h][w] = 0;

                let rev = Reverse((0i64, h as isize, w as isize));
                heap.push(rev);
            }
        }
    }

    // HW個の要素を取り出してくるので、O(HW log(HW))
    // 間に合う見込み

    while !heap.is_empty() {
        let Reverse((dist, h, w)) = heap.pop().unwrap();

        let neibours: Vec<(usize, usize)> = vec![(h - 1, w), (h + 1, w), (h, w - 1), (h, w + 1)]
            .iter()
            .filter(|&&(h, w)| 0 <= h && h < H as isize && 0 <= w && w < W as isize)
            .map(|&(h, w)| (h as usize, w as usize))
            .collect();

        for &(neibour_h, neibour_w) in neibours.iter() {
            if distsz[neibour_h][neibour_w] > dist + 1 {
                distsz[neibour_h][neibour_w] = dist + 1;
                let tpl = (dist + 1, neibour_h as isize, neibour_w as isize);
                heap.push(Reverse(tpl));
            }
        }
    }

    let mut ans = 0;
    for h in 0..H {
        for w in 0..W {
            ans = max(ans, distsz[h][w]);
        }
    }

    println!("{}", ans);
}