def a_darker_and_darker(H, W, Grid):

    def is_in_field(row, col):

        return (0 <= row < H) and (0 <= col < W)



    grid, q = [[None] * W for _ in range(H)], []

    # 黒マスがどこにあるかを調べる。ついでにgridを初期化

    for row in range(H):

        for col in range(W):

            if Grid[row][col] == '#':

                grid[row][col] = True

                q.append((row, col))

            else:

                grid[row][col] = False



    # '#'があるマスから上下左右に移動することを繰り返して任意のマスに到達する。

    # 何回繰り返せばすべてのマスに到達できるか？

    directions = ((-1, 0), (0, 1), (1, 0), (0, -1))  # 上右下左の隣接マスを指定

    ans = 0

    while q:

        tmp = []

        for row, col in q:

            for dr, dc in directions:

                nr, nc = row + dr, col + dc

                if is_in_field(nr, nc) and (not grid[nr][nc]):

                    grid[nr][nc] = True

                    tmp.append((nr, nc))

        ans += (1 if tmp else 0)

        q = tmp

    return ans



H, W = [int(i) for i in input().split()]

Grid = [eval(input()) for _ in range(H)]

print((a_darker_and_darker(H, W, Grid)))
# 参考: https://atcoder.jp/contests/agc033/submissions/5279051

def a_darker_and_darker(H, W, Grid):

    from scipy.ndimage import distance_transform_cdt

    # 2次元リストの各位置に対して、Falseとみなされる要素がある位置から

    # 最短の距離が格納された2次元リストを返す

    # 距離の測り方は、metricが'taxicab'だとマンハッタン距離に、

    # 'chessboard'だとチェビシェフ距離に基づく



    grid = [[1 if c == '.' else 0 for c in row] for row in Grid]

    return distance_transform_cdt(grid, metric='taxicab').max()



H, W = [int(i) for i in input().split()]

Grid = [eval(input()) for _ in range(H)]

print((a_darker_and_darker(H, W, Grid)))
def a_darker_and_darker(H, W, Grid):
    def is_in_field(row, col):
        return (0 <= row < H) and (0 <= col < W)

    grid, q = [[None] * W for _ in range(H)], []
    # 黒マスがどこにあるかを調べる。ついでにgridを初期化
    for row in range(H):
        for col in range(W):
            if Grid[row][col] == "#":
                grid[row][col] = True
                q.append((row, col))
            else:
                grid[row][col] = False
    # '#'があるマスから上下左右に移動することを繰り返して任意のマスに到達する。
    # 何回繰り返せばすべてのマスに到達できるか？
    directions = ((-1, 0), (0, 1), (1, 0), (0, -1))  # 上右下左の隣接マスを指定
    ans = 0
    while q:
        tmp = []
        for row, col in q:
            for dr, dc in directions:
                nr, nc = row + dr, col + dc
                if is_in_field(nr, nc) and (not grid[nr][nc]):
                    grid[nr][nc] = True
                    tmp.append((nr, nc))
        ans += 1 if tmp else 0
        q = tmp
    return ans


H, W = [int(i) for i in input().split()]
Grid = [eval(input()) for _ in range(H)]
print((a_darker_and_darker(H, W, Grid)))

# 参考: https://atcoder.jp/contests/agc033/submissions/5279051
def a_darker_and_darker(H, W, Grid):
    from scipy.ndimage import distance_transform_cdt

    # 2次元リストの各位置に対して、Falseとみなされる要素がある位置から
    # 最短の距離が格納された2次元リストを返す
    # 距離の測り方は、metricが'taxicab'だとマンハッタン距離に、
    # 'chessboard'だとチェビシェフ距離に基づく
    grid = [[1 if c == "." else 0 for c in row] for row in Grid]
    return distance_transform_cdt(grid, metric="taxicab").max()


H, W = [int(i) for i in input().split()]
Grid = [eval(input()) for _ in range(H)]
print((a_darker_and_darker(H, W, Grid)))

+# 参考: https://atcoder.jp/contests/agc033/submissions/5279051 -    def is_in_field(row, col): -        return (0 <= row < H) and (0 <= col < W) +    from scipy.ndimage import distance_transform_cdt -    grid, q = [[None] * W for _ in range(H)], [] -    # 黒マスがどこにあるかを調べる。ついでにgridを初期化 -    for row in range(H): -        for col in range(W): -            if Grid[row][col] == "#": -                grid[row][col] = True -                q.append((row, col)) -            else: -                grid[row][col] = False -    # '#'があるマスから上下左右に移動することを繰り返して任意のマスに到達する。 -    # 何回繰り返せばすべてのマスに到達できるか？ -    directions = ((-1, 0), (0, 1), (1, 0), (0, -1))  # 上右下左の隣接マスを指定 -    ans = 0 -    while q: -        tmp = [] -        for row, col in q: -            for dr, dc in directions: -                nr, nc = row + dr, col + dc -                if is_in_field(nr, nc) and (not grid[nr][nc]): -                    grid[nr][nc] = True -                    tmp.append((nr, nc)) -        ans += 1 if tmp else 0 -        q = tmp -    return ans +    # 2次元リストの各位置に対して、Falseとみなされる要素がある位置から +    # 最短の距離が格納された2次元リストを返す +    # 距離の測り方は、metricが'taxicab'だとマンハッタン距離に、 +    # 'chessboard'だとチェビシェフ距離に基づく +    grid = [[1 if c == "." else 0 for c in row] for row in Grid] +    return distance_transform_cdt(grid, metric="taxicab").max()