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

/* package whatever; // don't place package name! */
   
import java.util.*;
import java.lang.*;
import java.io.*;
   
/* Name of the class has to be "Main" only if the class is public. */
class Main
{
       
    public static final int[] vs = {1, 0, -1, 0};
   
    public static final double EPS = 1e-10;
       
    public static void bfs(final int H, final int W, final int sx, final int sy, boolean[][] is_wall, boolean[][] is_floor, double[][] expected, boolean is_spring){           
        LinkedList<Double> expected_queue = new LinkedList<Double>();
        LinkedList<Integer> x_queue = new LinkedList<Integer>();
        LinkedList<Integer> y_queue = new LinkedList<Integer>();
           
        expected_queue.add(expected[sy][sx]);
        x_queue.add(sx);
        y_queue.add(sy);
           
        while(!x_queue.isEmpty()){
            final int x = x_queue.poll();
            final int y = y_queue.poll();
               
            for(int v = 0; v < vs.length; v++){
                final int nx = x + vs[v];
                final int ny = y + vs[(v + 1) % vs.length];
                   
                if(nx < 0 || nx >= W || ny < 0 || ny >= H){
                    continue;   
                }else if(is_wall[ny][nx]){
                    continue;
                }
                
                ///System.out.println(nx + " " + ny + " " + expected[y][x] + " " + expected[ny][nx]);
             
                if(is_floor[ny][nx] && expected[ny][nx] > expected[y][x] + 1){
                	expected[ny][nx] = expected[y][x] + 1;
                    y_queue.add(ny);
                    x_queue.add(nx);
                }
            }
        }
    }
       
    public static void main (String[] args) throws java.lang.Exception
    {
        Scanner sc = new Scanner(System.in);
        {
            final int W = sc.nextInt();
            final int H = sc.nextInt();
               
            int sx = -1, sy = -1, gx = -1, gy = -1;
            boolean[][] is_floor = new boolean[H][W];
            boolean[][] is_wall = new boolean[H][W];
               
            LinkedList<Integer> spring_xs = new LinkedList<Integer>();
            LinkedList<Integer> spring_ys = new LinkedList<Integer>();
               
            for(int i = 0; i < H; i++){
                final char[] line = sc.next().toCharArray();
                for(int j = 0; j < W; j++){
                    if(line[j] != '#' && line[j] != '*'){
                        is_floor[i][j] = true;
                    }else if(line[j] == '*'){
                        spring_ys.add(i);
                        spring_xs.add(j);
                    }else if(line[j] == '#'){
                        is_wall[i][j] = true;
                    }
                       
                    if(line[j] == 's'){
                        sy = i;
                        sx = j;
                    }else if(line[j] == 'g'){
                        gy = i;
                        gx = j;
                    }
                }
            }
            
            final double INF = Long.MAX_VALUE;
            
            double upper = INF;
            double lower = 0;
            
            double[][] expected = new double[H][W];
            
            int counter = 0;
            while(upper - lower > EPS){
            	final double middle = (upper + lower) / 2;
            	counter++;
            
            	for(int i = 0; i < H; i++){
            		for(int j = 0; j < W; j++){
            			expected[i][j] = INF;
            		}
            	}
            	expected[gy][gx] = 0;
            	
            	for(Iterator<Integer> x_itr = spring_xs.iterator(), y_itr = spring_ys.iterator(); x_itr.hasNext() && y_itr.hasNext(); ){
            		final int x = x_itr.next();
            		final int y = y_itr.next();
            		
            		expected[y][x] = middle;
            	}
            	
            	bfs(H, W, gx, gy, is_wall, is_floor, expected, false);
            	/*for(int i = 0; i < H; i++){
            		for(int j = 0; j < W; j++){
            			System.out.printf("%3.0f ", expected[i][j] >= INF ? Double.NaN : expected[i][j]);
            		}
            		System.out.println();
            	}*/
            	
            	for(Iterator<Integer> x_itr = spring_xs.iterator(), y_itr = spring_ys.iterator(); x_itr.hasNext() && y_itr.hasNext(); ){
            		final int x = x_itr.next();
            		final int y = y_itr.next();
            		
            		bfs(H, W, x, y, is_wall, is_floor, expected, true);
            	}
            	/*
            	for(int i = 0; i < H; i++){
            		for(int j = 0; j < W; j++){
            			System.out.printf("%3.0f ", expected[i][j] >= INF ? Double.NaN : expected[i][j]);
            		}
            		System.out.println();
            	}*/
            	
            	double expected_sum = 0;
            	int count = 0;
            	for(int i = 0; i < H; i++){
            		for(int j = 0; j < W; j++){
            			if(!is_floor[i][j]){
            				continue;
            			}else if(i == gy && j == gx){
            				continue;
            			}
            			
            			count++;
            			expected_sum += expected[i][j];
            		}
            	}
            	
            	final double expected_value = expected_sum / count;
            	
            	if(expected_value < middle){
            		upper = middle;
            	}else if(expected_value > middle){
            		lower = middle;
            	}else{
            		upper = middle;
            		lower = middle;
            	}
            	
            	//System.out.println(upper + " " + middle + " " + lower + " " + expected_value + " "  + count);
            	
            	if(counter % 5 == 0){
            		System.gc();
            	}
            }
            
            System.out.printf("%.10f\n", expected[sy][sx]);
        }
    }
}