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)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using static System.Convert;
using static System.Math;
using static Constants;
using static Extensions;
using static MathExtensions;

public static class Program
{
    class State
    {
        public Point2 Point;
        public State PrevState;

        public State(Point2 point, State prev)
        {
            Point = point;
            PrevState = prev;
        }
    }

    public static void Solve()
    {
        var h = I;
        var w = I;
        var s = new char[h][];
        foreach (var i in Range(h)) s[i] = S.ToCharArray();
        var grid = new Grid2<char>(s);

        var queue = new Queue<State>();
        var visited = new HashSet<Point2>();
        queue.Enqueue(new State(Point2.Origin, null));

        while (queue.Any())
        {
            var state = queue.Dequeue();
            if (!visited.Add(state.Point)) continue;

            foreach (var unit in Point2.Units)
            {
                var nextPoint = state.Point + unit;

                if (nextPoint == grid.Size - new Point2(1, 1))
                {
                    var pathPoints = new HashSet<Point2>();
                    while (state != null)
                    {
                        pathPoints.Add(state.Point);
                        state = state.PrevState;
                    }
                    var ans = Point2.EnumerateInnerPoints(grid.Size)
                        .Count(p => grid[p] == '.' && !pathPoints.Contains(p)) - 1;
                    Answer(ans);
                }

                if (nextPoint.IsIn(grid.Size) && grid[nextPoint] == '.')
                    queue.Enqueue(new State(nextPoint, state));
            }
        }

        Answer(-1);
    }

    #region Scanners
    static TextScanner _ts;
    static char C => char.Parse(_ts.Next());
    static string S => _ts.Next();
    static int I => int.Parse(_ts.Next());
    static long L => long.Parse(_ts.Next());
    static BigInteger B => BigInteger.Parse(_ts.Next());
    static double D => double.Parse(_ts.Next());
    static decimal M => decimal.Parse(_ts.Next());
    #endregion

    public static void Main()
    {
        var sw = new StreamWriter(Console.OpenStandardOutput());
        sw.NewLine = "\n";
#if DEBUG
        sw.AutoFlush = true;
#else
        sw.AutoFlush = false;
#endif
        Console.SetOut(sw);
        _ts = new TextScanner(Console.In);
        Solve();
        Console.Out.Flush();
    }
}

public static partial class Extensions
{
}

#region Library
public struct Point2 : IEquatable<Point2>
{
    public Point2(int y, int x)
    {
        this.Y = y;
        this.X = x;
    }

    public int Y { get; }
    public int X { get; }

    public static readonly Point2 Origin
        = new Point2(0, 0);

    public static readonly IReadOnlyCollection<Point2> Units
        = new[] { new Point2(0, 1), new Point2(1, 0), new Point2(0, -1), new Point2(-1, 0) };

    public static IEnumerable<Point2> EnumerateInnerPoints(Point2 max)
        => EnumerateInnerPoints(Origin, max);

    public static IEnumerable<Point2> EnumerateInnerPoints(Point2 min, Point2 max)
    {
        if (min.X > max.X || min.Y > max.Y) throw new ArgumentException();
        for (var i = min.Y; i < max.Y; i++)
            for (var j = min.X; j < max.X; j++)
                yield return new Point2(i, j);
    }

    public static int ManhattanDistance(Point2 source, Point2 target)
        => System.Math.Abs(source.X - target.X) + System.Math.Abs(source.Y - target.Y);

    public static int ChebyshevDistance(Point2 source, Point2 target)
        => System.Math.Max(System.Math.Abs(source.X - target.X), System.Math.Abs(source.Y - target.Y));

    public static Point2 operator +(Point2 left, Point2 right)
        => new Point2(left.Y + right.Y, left.X + right.X);

    public static Point2 operator -(Point2 left, Point2 right)
        => new Point2(left.Y - right.Y, left.X - right.X);

    public static bool operator ==(Point2 left, Point2 right)
        => left.Equals(right);

    public static bool operator !=(Point2 left, Point2 right)
        => !left.Equals(right);

    public bool IsIn(Point2 max)
        => this.IsIn(Origin, max);

    public bool IsIn(Point2 min, Point2 max)
    {
        if (min.X > max.X || min.Y > max.Y) throw new ArgumentException();
        return min.Y <= this.Y && this.Y < max.Y && min.X <= this.X && this.X < max.X;
    }

    public bool Equals(Point2 other)
        => this.Y == other.Y && this.X == other.X;

    public override bool Equals(object obj)
        => obj is Point2 ? this.Equals((Point2)obj) : false;

    public override int GetHashCode()
        => unchecked((this.Y << 16) | this.X);

    public override string ToString()
        => $"{this.X} {this.Y}";
}

public class Grid2<T>
{
    private T[][] _grid;

    public Grid2(int height, int width) : this(new Point2(height, width)) { }

    public Grid2(Point2 size)
    {
        _grid = new T[size.Y][];
        for (var i = 0; i < _grid.Length; i++) _grid[i] = new T[size.X];
        this.Height = size.Y;
        this.Width = size.X;
        this.Size = size;
    }

    public Grid2(T[][] grid)
    {
        this.Height = grid.Length;
        this.Width = grid.Max(r => r.Length);
        this.Size = new Point2(this.Height, this.Width);
        _grid = new T[this.Height][];
        for (var i = 0; i < _grid.Length; i++)
        {
            _grid[i] = new T[this.Width];
            for (var j = 0; j < _grid[i].Length; j++) _grid[i][j] = grid[i][j];
        }
    }

    public int Height { get; }
    public int Width { get; }
    public Point2 Size { get; }

    public T this[Point2 point]
    {
        get { return _grid[point.Y][point.X]; }
        set { _grid[point.Y][point.X] = value; }
    }
}

public class TextScanner
{
    private readonly TextReader _tr;

    public TextScanner(TextReader tr)
    {
        _tr = tr;
    }

    public string Next()
    {
        var sb = new StringBuilder();
        int i;
        do
        {
            i = _tr.Read();
            if (i == -1) throw new EndOfStreamException();
        }
        while (char.IsWhiteSpace((char)i));
        while (i != -1 && !char.IsWhiteSpace((char)i))
        {
            sb.Append((char)i);
            i = _tr.Read();
        }
        return sb.ToString();
    }
}

public static class Constants
{
    public const int AnswerToLifeTheUniverseAndEverything = 42;
    public const string Yes = nameof(Yes);
    public const string No = nameof(No);
    public const string YES = nameof(YES);
    public const string NO = nameof(NO);
    public const string Possible = nameof(Possible);
    public const string Impossible = nameof(Impossible);
}

[DebuggerStepThrough]
public static partial class Extensions
{
    public static void Answer(object value)
    {
        Console.WriteLine(value);
        Exit(0);
    }

    public static void Assert(bool condition)
    {
        if (!condition) throw new Exception("Assertion failed");
    }

    public static string AsString(this IEnumerable<char> source) => new string(source.ToArray());

    public static Dictionary<T, int> Bucket<T>(this IEnumerable<T> source) where T : IEquatable<T>
    {
        var dict = new Dictionary<T, int>();
        foreach (var item in source) if (dict.ContainsKey(item)) dict[item]++; else dict[item] = 1;
        return dict;
    }

    public static int[] Bucket<T>(this IEnumerable<T> source, int maxValue, Func<T, int> selector)
    {
        var arr = new int[maxValue + 1];
        foreach (var item in source) arr[selector(item)]++;
        return arr;
    }

    public static IComparer<T> CreateDescendingComparer<T>()
        where T : IComparable<T>
        => Comparer<T>.Create((x, y) => y.CompareTo(x));

    public static IEnumerable<int> CumSum(this IEnumerable<int> source)
    {
        var sum = 0;
        foreach (var item in source) yield return sum += item;
    }

    public static IEnumerable<long> CumSum(this IEnumerable<long> source)
    {
        var sum = 0L;
        foreach (var item in source) yield return sum += item;
    }

    public static void Exit(int exitCode)
    {
        Console.Out.Flush();
        Environment.Exit(exitCode);
    }

    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source) action(item);
    }

    public static void ForEach<T, _>(this IEnumerable<T> source, Func<T, _> func)
    {
        foreach (var item in source) func(item);
    }

    public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> action)
    {
        var i = 0;
        foreach (var item in source) action(item, i++);
    }

    public static void ForEach<T, _>(this IEnumerable<T> source, Func<T, int, _> func)
    {
        var i = 0;
        foreach (var item in source) func(item, i++);
    }

    public static T Identity<T>(this T item) => item;

    public static IEnumerable<int> Range(int start, int end, int step = 1)
    {
        for (var i = start; i < end; i += step) yield return i;
    }

    public static IEnumerable<int> Range(int end) => Range(0, end);

    public static void Repeat(int count, Action action)
    {
        for (var i = 0; i < count; i++) action();
    }

    public static void Repeat(int count, Action<int> action)
    {
        for (var i = 0; i < count; i++) action(i);
    }

    public static IEnumerable<T> Repeat<T>(int count, Func<T> func)
    {
        for (var i = 0; i < count; i++) yield return func();
    }

    public static IEnumerable<T> Repeat<T>(int count, Func<int, T> func)
    {
        for (var i = 0; i < count; i++) yield return func(i);
    }

    public static void Swap<T>(ref T x, ref T y)
    {
        var tmp = x; x = y; y = tmp;
    }
}

[DebuggerStepThrough]
public static class MathExtensions
{
    public static int DivCeil(int left, int right)
        => left / right + (left % right == 0 ? 0 : 1);

    public static long DivCeil(long left, long right)
        => left / right + (left % right == 0L ? 0L : 1L);

    public static int Gcd(int left, int right)
    {
        int r;
        while ((r = left % right) != 0) { left = right; right = r; }
        return right;
    }

    public static long Gcd(long left, long right)
    {
        long r;
        while ((r = left % right) != 0L) { left = right; right = r; }
        return right;
    }

    public static BigInteger Gcd(BigInteger left, BigInteger right)
        => BigInteger.GreatestCommonDivisor(left, right);

    public static int HighestOneBit(int x)
    {
        x |= x >> 01;
        x |= x >> 02;
        x |= x >> 04;
        x |= x >> 08;
        x |= x >> 16;
        return x - (x >> 1);
    }

    public static long HighestOneBit(long x)
    {
        x |= x >> 01;
        x |= x >> 02;
        x |= x >> 04;
        x |= x >> 08;
        x |= x >> 16;
        x |= x >> 32;
        return x - (x >> 1);
    }

    public static int Lcm(int left, int right) => left / Gcd(left, right) * right;

    public static long Lcm(long left, long right) => left / Gcd(left, right) * right;

    public static BigInteger Lcm(BigInteger left, BigInteger right)
        => left / Gcd(left, right) * right;

    public static int Pow(int value, int exponent)
    {
        var r = 1;
        while (exponent > 0)
        {
            if ((exponent & 1) == 1) r *= value;
            value *= value;
            exponent >>= 1;
        }
        return r;
    }

    public static long Pow(long value, int exponent)
    {
        var r = 1L;
        while (exponent > 0)
        {
            if ((exponent & 1) == 1) r *= value;
            value *= value;
            exponent >>= 1;
        }
        return r;
    }

    public static long Fact(int value)
    {
        var r = 1L;
        for (var i = 2; i <= value; i++) r *= i;
        return r;
    }
}
#endregion