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 Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;
import java.util.ArrayDeque;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author silviase
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        Scanner in = new Scanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        ADarkerAndDarker solver = new ADarkerAndDarker();
        solver.solve(1, in, out);
        out.close();
    }

    static class ADarkerAndDarker {
        public void solve(int testNumber, Scanner in, PrintWriter out) {
            final int INF = (int) 1e9;
            int[] dx = {-1, 0, 0, 1};
            int[] dy = {0, -1, 1, 0};

            int h = in.nextInt();
            int w = in.nextInt();

            char[][] c = new char[h][w];
            for (int i = 0; i < h; i++) {
                c[i] = in.next().toCharArray();
            }
            int[][] man = new int[h + 1][w + 1];
            boolean[][] used = new boolean[h + 1][w + 1];

            for (int i = 0; i <= h; i++) {
                Arrays.fill(man[i], INF);
                Arrays.fill(used[i], false);
            }
            ArrayDeque<Integer> q = new ArrayDeque<>();


            for (int i = 0; i < h; i++) {
                for (int j = 0; j < w; j++) {
                    // 多点bfs
                    if (c[i][j] == '#') {
                        q.addLast(i * w + j);
                        used[i][j] = true;
                        man[i][j] = 0;
                    }
                }
            }

            while (!q.isEmpty()) {
                //out.println("q:" + q.peek());
                int now = q.pollFirst();
                for (int i = 0; i < 4; i++) {
                    int x = now / w;
                    int y = now % w;
                    int nx = x + dx[i];
                    int ny = y + dy[i];
                    if (!(0 <= nx && nx < h && 0 <= ny && ny < w)) continue;
                    if (!used[nx][ny]) {
                        used[nx][ny] = true;
                        man[nx][ny] = man[x][y] + 1;
                        q.addLast(nx * w + ny);
                    }
                }
            }

            int max = -1;
            for (int i = 0; i < h; i++) {
                // out.println(Arrays.toString(man[i]));
                for (int j = 0; j < w; j++) {
                    max = Math.max(max, man[i][j]);
                }
            }

            out.println(max);

        }

    }
}