Problem:
Score: 400 points

Problem statement

We have an H \times W grid whose squares are painted black or white. The square at the i-th row from the top and the j-th column from the left is denoted as (i, j).

Snuke would like to play the following game on this grid. At the beginning of the game, there is a character called Kenus at square (1, 1). The player repeatedly moves Kenus up, down, left or right by one square. The game is completed when Kenus reaches square (H, W) passing only white squares.

Before Snuke starts the game, he can change the color of some of the white squares to black. However, he cannot change the color of square (1, 1) and (H, W). Also, changes of color must all be carried out before the beginning of the game.

When the game is completed, Snuke's score will be the number of times he changed the color of a square before the beginning of the game. Find the maximum possible score that Snuke can achieve, or print -1 if the game cannot be completed, that is, Kenus can never reach square (H, W) regardless of how Snuke changes the color of the squares.

The color of the squares are given to you as characters s_{i, j}. If square (i, j) is initially painted by white, s_{i, j} is .; if square (i, j) is initially painted by black, s_{i, j} is #.

Constraints

H is an integer between 2 and 50 (inclusive).

W is an integer between 2 and 50 (inclusive).

s_{i, j} is . or # (1 \leq i \leq H, 1 \leq j \leq W).

s_{1, 1} and s_{H, W} are ..

Input

Input is given from Standard Input in the following format:

H W
s_{1, 1}s_{1, 2}s_{1, 3} ... s_{1, W}
s_{2, 1}s_{2, 2}s_{2, 3} ... s_{2, W}
: :
s_{H, 1}s_{H, 2}s_{H, 3} ... s_{H, W}

Output

Print the maximum possible score that Snuke can achieve, or print -1 if the game cannot be completed.

Sample Input 1

3 3
..#
#..
...

Sample Output 1

2

The score 2 can be achieved by changing the color of squares as follows:

Sample Input 2

10 37
.....................................
...#...####...####..###...###...###..
..#.#..#...#.##....#...#.#...#.#...#.
..#.#..#...#.#.....#...#.#...#.#...#.
.#...#.#..##.#.....#...#.#.###.#.###.
.#####.####..#.....#...#..##....##...
.#...#.#...#.#.....#...#.#...#.#...#.
.#...#.#...#.##....#...#.#...#.#...#.
.#...#.####...####..###...###...###..
.....................................

Sample Output 2

209

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

//
// ABC088D
// URL : https://atcoder.jp/contests/abc088/tasks/abc088_d
// 
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;

namespace AtCoder
{
    class ABC088D
    {
        public static readonly long MOD_CONST = 1000000007;//(long)Math.Pow(10, 9) + 7;


        static void Main(string[] args)
        {
            //出力高速化
            var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            Console.SetOut(sw);
            Solve();
            Console.Out.Flush();
        }
        public static readonly int[] dx = new int[4] { 1, -1, 0, 0 };
        public static readonly int[] dy = new int[4] { 0,  0, 1, -1 };
        public class Masu
        {
            public int h;
            public int w;
            public Masu(int _h, int _w) { h = _h; w = _w; }
        }
        public static void Solve()
        {
            var inputArray = Console.ReadLine().Split(' ').Select(_inputStr => int.Parse(_inputStr)).ToArray();
            int H = inputArray[0];//縦幅
            int W = inputArray[1];//横幅
            var Maze = new char[H, W];//迷路
            var steps = new int[H, W];//スタートからそのマスに行くまでかかった歩数

            int initBlackMasu = 0;//最初に黒く塗られている数
            for (int h = 0; h < H; ++h)
            {
                var s = Console.ReadLine();
                for(int w = 0; w < W; ++w) 
                {
                    char c = s[w];
                    Maze[h, w] = c;
                    steps[h, w] = 0;//最初は全部0歩とする
                    if(c == '#')
                    {
                        initBlackMasu++;
                    }
                }
            }
            var nextQueue = new Queue<Masu> ();
            nextQueue.Enqueue(new Masu(0, 0));
            bool canReach = false;//ゴールにたどり着けたか
            //BFS
            while(nextQueue.Count != 0)
            {
                var next = nextQueue.Dequeue();
                int h = next.h;
                int w = next.w;
                for (int i = 0; i < 4; ++i) {
                    int nh = h + dy[i];
                    int nw = w + dx[i];
                    if(nh < 0 || H <= nh) { continue; }
                    if(nw < 0 || W <= nw) { continue; }
                    if(Maze[nh, nw] == '#') { continue; }
                    if(steps[nh, nw] > 0) { continue; }//0より大きいならもう通ったマス
                    steps[nh, nw] = steps[h,w] + 1;
                    if(nh == H-1 && nw == W-1)//ゴールに着いた
                    {
                        canReach = true;
                        break;
                    }
                    nextQueue.Enqueue(new Masu(nh, nw));
                }
                if(canReach == true)
                {
                    break;
                }
            }
            //最短経路=最小の手数で、ゴールまでいける経路。つまり、この経路上のマス以外は全部黒く塗ってもいい。
            //よって最短経路と最初からある壁以外のマスの数が最大スコアとなる
            int ans = 0;
            if (canReach == true)
            {
                //最短経路を通った場合の、通ったマス数
                int goalStep = steps[H - 1, W - 1];
                ans = (H * W) - initBlackMasu - goalStep - 1;//1は最初にけぬすくんがいるマスの分(このマスは塗れない)
            }
            else//たどり着けない場合
            {
                ans = -1;
            }
            Console.WriteLine(ans);
        }


        //---------------------------------------------------------------------------------
        #region MyLib

        /// <summary>
        /// グラフ系
        /// </summary>
        public class Node
        {
            public Node(long val){
                this.Value = val;
                this.Children = new List<Node>();
            }

            public Node(long val, List<Node> children)
            {
                this.Value = val;
                this.Children = children;
            }

            public long Value { get; set; }
            public List<Node> Children { get; set; }
        }

        /// <summary>
        /// Clamping
        /// </summary>
        /// <typeparam name="T">比較型</typeparam>
        /// <param name="x">clampしたい値</param>
        /// <param name="min">最小値</param>
        /// <param name="max">最大値</param>
        /// <returns>clamp済みの値</returns>
        public static T Clamp<T>(T x, T min, T max) where T : IComparable<T>
        {
            if (x.CompareTo(min) < 0) { return min; }
            else if (x.CompareTo(max) > 0) { return max; }
            else return x;
            //return Math.Max(Math.Min(x, max), min);
        }

        /// <summary>
        /// 指定された底log_baseでの, 対数を計算
        /// </summary>
        /// <param name="x"></param>
        /// <param name="log_base">指定の底</param>
        /// <returns></returns>
        public static double LogBase(double x, double log_base)
        {
            //log_b(N) = log_a(N) / log_a(B)より
            return Math.Log(x) / Math.Log(log_base);
        }

        /// <summary>
        /// 初項a, 公差d, 項数nの数列の和
        /// </summary>
        /// <param name="n">求めたいところ</param>
        /// <returns>初項からxまで足した値</returns>
        static long SumSeries(long a, long d, long n)
        {
            return (2 * a + (n - 1) * d) * n / 2;
        }
        /// <summary>
        /// 累積和の配列を計算する
        /// Sum[ a[0], a[i] )がs[i+1]に入っている
        /// s[0]  : 0                //一切和を取らない場合
        /// s[1]  : ls[0]            //a[0]   + s[0] = a[0]
        /// s[2]  : ls[1] + s[1]     //a[1]   + a[0]
        /// ...
        /// s[N]  : ls[N-1] + s[N-1] //a[N-1] + ... + a[0]
        /// s[N+1]: ls[N] + s[N]     //a[N]   + ... + a[0]
        /// 
        /// 例: [1, 7)の和(a[1] + ... + a[6])
        /// s[1] = a[0] //[0, 1)
        /// s[7] = a[0] + a[1] + ... + a[6] //[0, 7)
        /// よってs[7] - s[1]);
        /// </summary>
        /// <param name="ls">計算したい配列</param>
        /// <returns>累積和配列</returns>
        static List<long> AggregateSumList(List<long> a)
        {
            var s = new List<long>(a.Count + 1);
            if (a.Count == 0)
            {
                return s;
            }
            s.Add(0);//s[0] = 0
            for (int i = 0; i < a.Count; ++i)
            {
                s.Add(a[i] + s[i]);
            }
            return s;
        }


        /// <summary>
        /// 与えられた数が素数かどうかを計算する
        /// </summary>
        /// <param name="num">対象数</param>
        /// <returns>true:素数, false:素数ではない(合成数)</returns>
        public static bool isPrime(int num)
        {
            if (num < 2) return false;
            else if (num == 2) return true;
            else if (num % 2 == 0) return false;

            double sqrtNum = Math.Sqrt(num);
            for (int i = 3; i <= sqrtNum; i += 2)
            {
                if (num % i == 0)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 順列mPnを計算する
        /// </summary>
        /// <param name="m"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static long Permutation(long m, long n)
        {
            long ret = 1;
            for (var i = 0; i < n; ++i)
            {
                ret *= m - i;
            }
            return ret;
        }
        /// <summary>
        /// 組み合わせmCnを計算する
        /// </summary>
        /// <param name="m"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        public static long Combination(long m, long n)
        {
            if (m == n || n == 0)
            {
                return 1;
            }
            long ans = 1;
            for (var i = 1; i <= n; ++i)
            {
                ans = ans * (m - i + 1) / i;
            }
            return ans;
        }

        static long Gcd(long m, long n)
        {
            if (n == 0) return m;
            return Gcd(n, m % n);
        }

        static long Lcm(long m, long n)
        {
            var gcd = Gcd(m, n);
            //return (m * n) / gcd;
            return m / gcd * n;//桁あふれ対策
        }
        #endregion MyLib
    }
}