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 Ruby (judge verdict: Memory Limit Exceeded)

class Heap
	require 'forwardable'
	extend Forwardable

	def initialize
		@array = []
		@index = {}
	end

	def add(obj, key)
		@array << [obj, key]
		@index[obj] = @array.size - 1
		lift_up(@array.size - 1)
	end

	def swap(i, j)
		u = @array[i]
		v = @array[j]
		@index[u[0]], @index[v[0]] = j, i
		@array[i], @array[j] = v, u
	end

	def lift_up(i)
		return if i == 0
		j = (i - 1) / 2
		if @array[i][1] < @array[j][1]
			swap(i, j)
			lift_up(j)
		end
	end

	def del_min
		raise "heap is empty!" if empty?
		min = @array[0]
		if size > 1
			swap(0, @array.size-1)
			@array.pop
			lift_down(0)
		else
			@array.pop
		end
		@index.delete(min[0])
		min
	end

	def inc_key(obj, diff)
		i = @index[obj]
		@array[i][1] += diff
		lift_down(i)
	end

	def dec_key(obj, diff)
		i = @index[obj]
		@array[i][1] -= diff
		lift_up(i)
	end

	def update_key(obj, new_key)
		i = @index[obj]
		return unless i
		return if new_key >= @array[i][1]
		@array[i][1] = new_key
		lift_up(i)
	end

	def min_obj
		@array[0][0]
	end

	def min_key
		@array[0][1]
	end

	def lift_down(i)
		j = 2 * i + 1
		k = j + 1
		if k >= size
			return if j >= size
			if @array[i][1] > @array[j][1]
				swap(i, j)
				lift_down(j)
			end
		else
			l = (@array[j][1] < @array[k][1] ? j : k)
			if @array[i][1] > @array[l][1]
				swap(i, l)
				lift_down(l)
			end
		end
	end

	def_delegators :@array, :empty?, :size
end

module Graphical
	require 'set'

	def reachable_from(s, max_depth = nil)
		reached = Set[s]
		queue = [s]
		depth = 0
		loop {
			break if max_depth && depth >= max_depth
			next_queue = []
			until queue.empty?
				u = queue.shift
				each_out_connection_of(u){|v, _|
					next if reached.include?(v)
					reached << v
					next_queue << v
				}
			end
			break if next_queue.empty?
			queue = next_queue
			depth += 1
		}
		return reached
	end
	
	def dijkstra(start)
		raise "start must be Enumerable" if !start.kind_of?(Enumerable)
		h = Heap.new
		reached = Set[*start.to_a]
		start.each{|s| h.add(s, 0)}

		dist = {}
		until h.empty?
			u, key = h.del_min
			return key if block_given? && yield(u, key)
			dist[u] = key
			each_out_connection_of(u){|v, l|
				d = dist[u] + l
				if reached.include?(v)
					h.update_key(v, d)
				else
					h.add(v, d)
					reached << v
				end
			}
		end
		block_given? ? nil : dist
	end

	def bidir_dijkstra(s, t)
		f_dist = {}
		b_dist = {}

		f_heap = Heap.new
		b_heap = Heap.new

		f_heap.add(s, 0)
		b_heap.add(t, 0)

		f_reached = Set[s]
		b_reached = Set[t]

		f_current_dist = b_current_dist = 0
		best = Float::INFINITY

		loop {
			if !f_heap.empty?
				u, key = f_heap.del_min
				f_dist[u] = key
				f_current_dist = key
				each_out_connection_of(u){|v, l|
					d = f_dist[u] + l
					if b_dist[v]
						path_len = d + b_dist[v]
						best = path_len if path_len < best
					end
					if f_reached.include?(v)
						f_heap.update_key(v, d)
					else
						f_heap.add(v, d)
						f_reached << v
					end
				}
			end

			if !b_heap.empty?
				u, key = b_heap.del_min
				b_dist[u] = key
				b_current_dist = key
				each_in_connection_of(u){|v, l|
					d = b_dist[u] + l
					if f_dist[v]
						path_len = d + f_dist[v]
						best = path_len if path_len < best
					end
					if b_reached.include?(v)
						b_heap.update_key(v, d)
					else
						b_heap.add(v, d)
						b_reached << v
					end
				}
			end

			return best if f_current_dist + b_current_dist >= best
			return nil if f_heap.empty? && b_heap.empty?
		}
	end

	def a_star(start)
		raise "a_star need termination condition" unless block_given?
		h = Heap.new
		reached = Set[start]
		h.add(start, [a_star_heuristic(start), 0])

		dist = {}
		until h.empty?
			u, (e, d) = h.del_min
			return d if yield(u, dist)
			dist[u] = d
			each_out_connection_of(u){|v, l|
				d = dist[u] + l
				e = d + a_star_heuristic(v)
				if reached.include?(v)
					h.update_key(v, [e, d])
				else
					h.add(v, [e, d])
					reached << v
				end
			}
		end
		block_given? ? nil : dist
	end

	#make_variations :bidir_dijkstra

	def prim(start)
		h = Heap.new
		h.add(start, 0)
		reached = Set[start]
		tree_len = 0

		until h.empty?
			u, key = h.del_min
			tree_len += key

			each_connection_of(u){|v, d|
				if reached.include?(v)
					h.update_key(v, d)
				else
					h.add(v, d)
					reached << v
				end
			}
		end
		tree_len
	end
end

class Graph
	include Graphical

	def initialize(*options)
		@options = Set[*options]
	end

	def add_node(property = {})
		Node.new(property)
	end

	def add_edge(u, v, property = {})
		e = Edge.new(u, v, property)
		u.add_edge(e)
		v.add_edge(e)
		e
	end
	
	def del_edge(e)
		u, v = e.from, e.to
		u.del_edge(e)
		v.del_edge(e)
		e
	end

	class Node
		def initialize(property)
			@property = property
			@edges = Set.new
		end

		def add_edge(e)
			@edges << e
		end

		def del_edge(e)
			@edges.delete(e)
		end

		def to_s
			@property[:name] || super
		end

		def each_edge
			@edges.each{|e| 
				yield e
			}
		end

		attr_reader :property
	end

	class Edge
		def initialize(u, v, property)
			@opposite = {u => v, v => u}
			@property = property
		end
		attr_reader :opposite, :property

		def to_s
			@property[:name] || super
		end

		def length
			@property[:length] || 1
		end
	end

	def each_out_connection_of(u)
		u.each_edge{|e|
			yield(e.opposite[u], e.length)
		}
	end

	alias :each_in_connection_of :each_out_connection_of
end

w, h = gets.split.map &:to_i
a = (1..h).map{ gets.chomp.split("") }

g = Graph.new
nodes = (0..h-1).map{|i| (0..w-1).map{|j| g.add_node(:name => [i,j]) } }
start = goal = nil

tiles = []
(1..h-2).each{|i|
	(1..w-2).each{|j|
		start = nodes[i][j] if a[i][j] == ?s
		goal = nodes[i][j] if a[i][j] == ?g
		tiles << nodes[i][j] if a[i][j] !~ /[#*g]/
		next if a[i][j] =~ /[#*]/
		if a[i+1][j] !~ /[#*]/
			g.add_edge(nodes[i][j], nodes[i+1][j])
		end
		if a[i][j+1] !~ /[#*]/
			g.add_edge(nodes[i][j], nodes[i][j+1])
		end
	}
}

g.dijkstra([goal]).each{|v, d|
	v.property[:dist] = d
}

springs = Set.new 
(1..h-2).each{|i|
	(1..w-2).each{|j|
		next if a[i][j] == ?#
		springs << nodes[i][j] if a[i][j] == ?*
		if a[i+1][j] != ?# && (a[i][j] == ?* || a[i+1][j] == ?*)
			g.add_edge(nodes[i][j], nodes[i+1][j])
		end
		if a[i][j+1] != ?# && (a[i][j] == ?* || a[i][j+1] == ?*)
			g.add_edge(nodes[i][j], nodes[i][j+1])
		end
	}
}

g.dijkstra(springs).each{|v, d|
	v.property[:to_spring] = d
}

if !start.property[:to_spring]
	puts start.property[:dist]
	exit
end

e_min = 0.0
e_max = 1e20

loop.with_index {|_, itr|
	#p itr
	e_center = (e_min + e_max)/2
	exp = tiles.map{|v|
		[ 
			v.property[:dist] || Float::INFINITY,
			(v.property[:to_spring] || Float::INFINITY) + e_center
		].min
	}.inject(0, :+) / tiles.size.to_f
	if e_center < exp
		e_min = e_center
	else
		e_max = e_center
	end
	break if e_max - e_min < 1e-10
}

printf("%.11f\n", 
	[
		start.property[:dist] || Float::INFINITY,
		(start.property[:to_spring] || Float::INFINITY) + e_min
	].min)