### BUGGY CODE ###


import numpy as np
from collections import deque

def parse():
  H, W = map(int, input().split(" "))
  grid = [list(input()) for y in range(H)]
  return H, W, grid

def print_grid(grid):
  H = len(grid)
  print("grid:")
  for line in grid:
    for c in line:
      print(c, end="")
    print("")

def main():
  H, W, grid = parse()
  # print(H, W)
  # print_grid(grid)

  dark_points = [(x + 1, y + 1) for x in range(W) for y in range(H) if grid[y][x] == "#"]

  visited = [[True if x == 0 or y == 0 or x == W + 1 or y == H + 1 else False for x in range(W + 2)] for y in range(H + 2)]
  for x, y in dark_points:
    visited[y][x] = True
  # for y in range(H + 2):
  #   print(visited[y])
  # exit(0)

  # visited = np.zeros((H, W), int)
  # for y in range(H):
  #   for x in range(W):
  #     if grid[y][x] == ".":
  #       visited[y][x] = H * W

  # for y in range(1, H):  # ↓
  #   visited[y][:] = np.minimum(visited[y][:], visited[y - 1][:] + 1)

  # for y in range(H - 2, -1, -1):
  #   visited[y, :] = np.minimum(visited[y, :], visited[y + 1][:] + 1)

  # for x in range(1, W):
  #   visited[:, x] = np.minimum(visited[:, x], visited[:, x - 1] + 1)

  # for x in range(W - 2, -1, -1):
  #   visited[:, x] = np.minimum(visited[:, x], visited[:, x + 1] + 1)

  # print(dark_points)
  # exit(0)

  q = dark_points
  ans = 0
  while len(q) > 0:
    ans += 1
    next_q = []
    for x, y in q:
      if not visited[y - 1][x]: # 上
        visited[y - 1][x] = ans
        next_q.append((x, y - 1))
      if not visited[y + 1][x]: # 下
        visited[y + 1][x] = ans
        next_q.append((x, y + 1))
      if not visited[y][x - 1]: # 左
        visited[y][x - 1] = ans
        next_q.append((x - 1, y))
      if not visited[y][x + 1]: # 右
        visited[y][x + 1] = ans
        next_q.append((x + 1, y))
      
    # for y in range(H + 2):
    #   print(visited[y])
    # input()
    
    q = next_q

  print(ans - 1)

if __name__ == "__main__":
  main()

### FIXED CODE ###


import numpy as np

def parse():
  H, W = map(int, input().split(" "))
  grid = [list(input()) for y in range(H)]
  return H, W, grid

def print_grid(grid):
  H = len(grid)
  print("grid:")
  for line in grid:
    for c in line:
      print(c, end="")
    print("")

def main():
  H, W, grid = parse()
  # print(H, W)
  # print_grid(grid)

  # visited = [[W * H if grid[y][x] == "." else 0 for x in range(W)] for y in range(H)]
  visited = np.zeros((H, W), int)
  for y in range(H):
    # visited.append([])
    for x in range(W):
      if grid[y][x] == ".":
        visited[y][x] = H * W

  for y in range(1, H):  # ↓
    # 要素ごとの処理
    # print(visited)
    visited[y][:] = np.minimum(visited[y][:], visited[y - 1][:] + 1)
    # print(visited)
    # input()
    # print(visited[y])
    # exit(0)

  for y in range(H - 2, -1, -1):
    visited[y, :] = np.minimum(visited[y, :], visited[y + 1][:] + 1)

  for x in range(1, W):
    visited[:, x] = np.minimum(visited[:, x], visited[:, x - 1] + 1)

  for x in range(W - 2, -1, -1):
    visited[:, x] = np.minimum(visited[:, x], visited[:, x + 1] + 1)

  # print(visited)
  # exit(0)

  # max_len = 0
  # for y in range(H):
  #   max_val = max(visited[y])
  #   max_len = max_len if max_len > max_val else max_val
  # print(max_len)
  print(np.max(visited))

if __name__ == "__main__":
  main()