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 Scala (2.11.7) (judge verdict: Time Limit Exceeded)

import java.io.{BufferedReader, InputStreamReader}
import java.util.Scanner

import scala.collection.mutable


object Main {


  def read() = {
    val sc = new Scanner(System.in)


    val h, w = sc.nextInt()
    val a = for (i <- 0 until h) yield sc.next()
    //val a = IndexedSeq.fill(h)(sc.next())
    //IndexedSeq.fill(w,h)(sc.nextInt())
    (w, h, a)
  }

  def read2() = {
    val input = io.Source.stdin.getLines()
    val (h, w) = {
      val strs = input.next().split(" ")
      (strs(0).toInt, strs(1).toInt)
    }
    val a = for (i <- 0 until h) yield input.next()
    (w, h, a)
  }

  def read3() = {
    val in = new BufferedReader(new InputStreamReader(System.in))
    val Array(h, w) = in.readLine().split(" ").map(_.toInt)
    val a = for (i <- 0 until h) yield in.readLine()
    (w, h, a)
  }

  def solve(w: Int, h: Int, a: IndexedSeq[String]): Int = {
    def isWithin(x: Int, y: Int): Boolean = 0 <= x && x < w && 0 <= y && y < h

    def nextList(x: Int, y: Int): IndexedSeq[(Int, Int)] = {
      IndexedSeq((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)).filter { case (x0, y0) => isWithin(x0, y0) }
    }

    def printArray2D(arr: Array[Array[Char]]): Unit = {
      arr.foreach { row =>
        row.foreach(print)
        println()
      }
      println()
    }


    def bfs(): Int = {
      val open = mutable.Queue.empty[(Int, Int)]
      val dist = Array.fill(h, w)(h + w)
      // h + w: enough large
      val visited = Array.fill(h, w)(false)


      for (y <- 0 until h; x <- 0 until w if a(y)(x) == '#') {
        open.enqueue((x, y))
        dist(y)(x) = 0
        visited(y)(x) = true
      }
      var maxDist = 0

      def update(x: Int, y: Int, xNext: Int, yNext: Int) = {
        if (isWithin(xNext, yNext) && !visited(yNext)(xNext)) {
          open.enqueue((xNext, yNext))
          dist(yNext)(xNext) = dist(y)(x) + 1
          maxDist = math.max(maxDist, dist(yNext)(xNext))
          visited(yNext)(xNext) = true
        }
      }

      while (open.nonEmpty) {
        val (x, y) = open.dequeue()
        var xNext = x + 1
        var yNext = y
        if (isWithin(xNext, yNext) && !visited(yNext)(xNext)) {
          open.enqueue((xNext, yNext))
          dist(yNext)(xNext) = dist(y)(x) + 1
          maxDist = math.max(maxDist, dist(yNext)(xNext))
          visited(yNext)(xNext) = true
        }

        xNext = x - 1
        yNext = y
        if (isWithin(xNext, yNext) && !visited(yNext)(xNext)) {
          open.enqueue((xNext, yNext))
          dist(yNext)(xNext) = dist(y)(x) + 1
          maxDist = math.max(maxDist, dist(yNext)(xNext))
          visited(yNext)(xNext) = true
        }

        xNext = x
        yNext = y + 1
        if (isWithin(xNext, yNext) && !visited(yNext)(xNext)) {
          open.enqueue((xNext, yNext))
          dist(yNext)(xNext) = dist(y)(x) + 1
          maxDist = math.max(maxDist, dist(yNext)(xNext))
          visited(yNext)(xNext) = true
        }

        xNext = x
        yNext = y - 1
        if (isWithin(xNext, yNext) && !visited(yNext)(xNext)) {
          open.enqueue((xNext, yNext))
          dist(yNext)(xNext) = dist(y)(x) + 1
          maxDist = math.max(maxDist, dist(yNext)(xNext))
          visited(yNext)(xNext) = true
        }


      }
      maxDist
    }

    bfs()
  }

  //719ms
  def bench(): Unit = {
    val w = 1000
    val h = 1000
    val open = Array.fill[(Int, Int)](w * h)((0, 0))
    var openLen = 0
    val next = Array.fill[(Int, Int)](w * h)((0, 0))
    var nextLen = 0
  }


  //527ms
  def bench2(): Unit = {
    val w = 1000
    val h = 1000
    val openX = Array.fill[Int](w * h)(0)
    val openY = Array.fill[Int](w * h)(0)
    var openLen = 0
    val nextX = Array.fill[Int](w * h)(0)
    val nextY = Array.fill[Int](w * h)(0)
    var nextLen = 0
  }

  // 1524ms (solve実行時間)
  def makeTestCase() = {
    val w = 1000
    val h = 1000
    val a = (for (y <- 0 until h) yield {
      for (x <- 0 until w) yield {
        if (y == 500 && x == 500) '#' else '.'
      }
    }).map(_.mkString)
    (w, h, a)
  }

  // 1524ms (solve実行時間)
  def makeTestCase2() = {
    val w = 1000
    val h = 1000
    val a = (for (y <- 0 until h) yield {
      for (x <- 0 until w) yield {
        if (y == 0 && x == 0) '#' else '.'
      }
    }).map(_.mkString)
    (w, h, a)
  }

  def printExecutionTime(proc: => Unit): Unit = {
    val start = System.currentTimeMillis
    proc
    val duration = System.currentTimeMillis - start
    println(s"$duration ms")
  }

  def main(args: Array[String]): Unit = {
    val (w, h, a) = read2()
    //val (w, h, a) = makeTestCase2()
    //printExecutionTime({
    println(solve(w, h, a))
    //bench2()
    //})
  }
}