Problem:
Problem G: スプリング・タイル

ある朝、あなたが目覚めると、そこはバネだらけの迷宮の中だった。

なぜ自分がこんな見知らぬ場所にいるのかはわからない。この場でじっと助けを待つという選択肢も
あるにはあるが、こういった迷宮の中に長居していると、いつかは必ず突風が吹いてきて吹き飛ばさ
れてしまうことを、あなたは経験上知っていた。しかし、突風が吹いてくるまでの時間は判断のしよ
うがない。そこであなたは、迷宮から脱出するまでに必要な移動回数の期待値が最小になるように行
動するのが最善の戦略だと考えた。

足元に落ちていた正体不明の巻物を拾ってためしに読んでみたところ、偶然にも迷宮の全体マップを
知覚することができた。さらに、たまたま持っていた草を飲むことで、すべてのワナの位置も知るこ
とができた。どうやらこの迷宮には、危険なモンスターやバネ以外のワナは存在しないらしい。

この迷宮は、いくつかの種類のタイルが長方形に並んだ形をしており、たとえば以下のようにあらわ
される。

########
#..##g.#
#*#.*#.#
#......#
#*s#*.*#
########

「.」：床。この上なら自由に歩き回ることができる。

「#」：壁。あなたは壁の中に入ることはできない。

「s」：あなたの最初の位置。このタイルの下は床になっている。

「g」：階段。このタイルの上に乗れば、迷宮を脱出したことになる。

「*」：バネ。このタイルの上に乗ると、いずれかの床の上（階段、バネのタイルは除く）にランダムに飛ばされる。それぞれの床に飛ばされる確率はすべて等しい。

タイルの種類は、この５つのいずれかである。

あなたは、現在乗っているタイルから隣り合ったタイルへ、上下左右いずれかの方向に１マスずつ移
動することができる。ただし、ナナメに移動することはできない。

迷宮のマップが与えられたとき、最善の戦略をとった場合に迷宮から脱出するまでに必要な移動回数
の期待値を求めよ。バネで飛ばされるのは移動回数には含めない。

Input

W H

c11 c12 ... c1w

c21 c22 ... c2w

::    :

ch1 ch2 ... ccw

入力の１行目には、整数W（3 ≤ W ≤ 500）と整数H（3 ≤ H ≤ 500）が、この順に空白区切りで書かれている。整数W は迷宮の横幅を、整数H は迷宮の縦幅をあらわす。

続くH 行には、迷宮のマップをあらわすW 個の文字が書かれている（空白区切りではない）。この部分の形式は、先に挙げた例のとおりである。なお、データ中に「s」と「g」は、それぞれちょうど１回ずつ出現する。また、迷宮の周囲１マスは、必ず壁で囲まれている。

なお、与えられる迷宮では、どのように移動し、バネでどのように飛ばされたとしても、「バネで飛
ばされる床を任意に設定できたとしても脱出不可能な状態」に陥ることはないと仮定してよい。

Output

最善の戦略をとったときに、脱出までにかかる移動回数の期待値を出力せよ。出力は誤差を含んでい
てもよいが、真の値との相対誤差が10-9 未満でなければならない。

Sample Input 1

8 6
########
#..##g.#
#*#.*#.#
#......#
#*s#*.*#
########

Sample Output 1

5.857142857143

Sample Input 2

21 11
#####################
#*#*.*.*.*.*.*.*.*#*#
#*#...............#*#
#*#.#.#.#.#.#.#.#.#*#
##.#.#.#.#.#.#.#.#.##
#...................#
##.#.#.#.#.#.#.#.#.##
#s#.#.#.#.#.#.#.#.#g#
#...................#
#...................#
#####################

Sample Output 2

20.000000000000

Sample Input 3

9 8
#########
#...#*.*#
#.*.#...#
#...#*.*#
#########
#.s....g#
#.*#.*..#
#########

Sample Output 3

5.000000000000

Solution in Scala (judge verdict: Accepted)

import scala.annotation.tailrec
import scala.collection.mutable
import scala.io.StdIn._
object Main extends App {
  val Array(w, h) = readLine.trim.split(' ').map(_.toInt)
  val arg = Array.tabulate(h){ _ ⇒ readLine.trim}
  val start = (0 until h).flatMap(y ⇒ (0 until w).find(x ⇒ arg(y)(x) == 's').map(x ⇒ Coordinate(x, y))).head
  val goal = (0 until h).flatMap(y ⇒ (0 until w).find(x ⇒ arg(y)(x) == 'g').map(x ⇒ Coordinate(x, y))).head
  val state = arg.map{line ⇒ line.map{
    case '#' ⇒ Wall
    case '.' | 's' ⇒ Empty
    case 'g' ⇒ Stair
    case '*' ⇒ Spring
    case _ ⇒ ???
  }.toArray}
  val minFromGoal = Array.fill(h){Array.fill(w){Double.MaxValue / 3}}
  minFromGoal(goal.y)(goal.x) = 0
  val queue = mutable.Queue[Coordinate](goal)
  while (queue.nonEmpty) {
    val current = queue.dequeue()
    for (next ← current.neighbor if (0 until h).contains(next.y) && (0 until w).contains(next.x) && state(next.y)(next.x) == Empty) {
      if (minFromGoal(next.y)(next.x) > minFromGoal(current.y)(current.x) + 1) {
        minFromGoal(next.y)(next.x) = minFromGoal(current.y)(current.x) + 1
        queue.enqueue(next)
      }
    }
  }
  val minToSpring = Array.fill(h){Array.fill(w){Double.MaxValue / 3}}
  for (spring ← (0 until h).flatMap(y ⇒ (0 until w).collect{case x if state(y)(x) == Spring ⇒ Coordinate(x, y)})){
    minToSpring(spring.y)(spring.x) = 0
    queue.enqueue(spring)
  }
  while(queue.nonEmpty) {
    val current = queue.dequeue()
    for (next ← current.neighbor if (0 until h).contains(next.y) && (0 until w).contains(next.x) && state(next.y)(next.x) == Empty) {
      if (minToSpring(next.y)(next.x) > minToSpring(current.y)(current.x) + 1) {
        minToSpring(next.y)(next.x) = minToSpring(current.y)(current.x) + 1
        queue.enqueue(next)
      }
    }
  }
  val empties = (0 until h).flatMap(y ⇒ (0 until w).collect{case x if state(y)(x) == Empty ⇒ Coordinate(x, y)})
  var min = 0d
  var max = Double.MaxValue / 2
  while (min * 1.000000000000001d < max) {
    val mid = (min + max) / 2
    if (canReach(mid)) max = mid
    else min = mid
  }
  println(f"${math.min(minToSpring(start.y)(start.x) + max, minFromGoal(start.y)(start.x))}%.12f")
  def canReach(estimated: Double): Boolean = empties.map{case Coordinate(x, y) ⇒ math.min(minToSpring(y)(x) + estimated, minFromGoal(y)(x))}.sum <= estimated * empties.length
  sealed trait State
  case object Spring extends State
  case object Wall extends State
  case object Empty extends State
  case object Stair extends State
  case class Coordinate(x: Int, y: Int) {
    def neighbor: List[Coordinate] = List(Coordinate(x + 1, y), Coordinate(x - 1, y), Coordinate(x, y + 1), Coordinate(x, y - 1))
  }
}