Problem:
Score : 400 points

Problem Statement

Takahashi has a maze, which is a grid of H \times W squares with H horizontal rows and W vertical columns.

The square at the i-th row from the top and the j-th column is a "wall" square if S_{ij} is #, and a "road" square if S_{ij} is ..

From a road square, you can move to a horizontally or vertically adjacent road square.

You cannot move out of the maze, move to a wall square, or move diagonally.

Takahashi will choose a starting square and a goal square, which can be any road squares, and give the maze to Aoki.

Aoki will then travel from the starting square to the goal square, in the minimum number of moves required.

In this situation, find the maximum possible number of moves Aoki has to make.

Constraints

1 \leq H,W \leq 20

S_{ij} is . or #.

S contains at least two occurrences of ..

Any road square can be reached from any road square in zero or more moves.

Input

Input is given from Standard Input in the following format:

H W
S_{11}...S_{1W}
:
S_{H1}...S_{HW}

Output

Print the maximum possible number of moves Aoki has to make.

Sample Input 1

3 3
...
...
...

Sample Output 1

4

If Takahashi chooses the top-left square as the starting square and the bottom-right square as the goal square, Aoki has to make four moves.

Sample Input 2

3 5
...#.
.#.#.
.#...

Sample Output 2

10

If Takahashi chooses the bottom-left square as the starting square and the top-right square as the goal square, Aoki has to make ten moves.

Solution in C# (.NET Core 3.1.201) (judge verdict: Wrong Answer)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
 
namespace AtCoder
{
    static class Program_D
    {
        class Solver
        {
            int ri => sc.Integer();
            long rl => sc.Long();
            double rd => sc.Double();
            string rs => sc.Scan();
            public StreamScanner sc = new StreamScanner(Console.OpenStandardInput());
            private int[][] cell;
            private int[] s;
            private int h;
            private int w;
            private Queue<int[]> q;
            private int maxDistance;
            private int[] maxPos;


            // 151-D Maze Master
            public void Solve()
            {
                h = ri;
                w = ri;
                var sOrg = new int[h*w];
                for (int y = 0; y < h; ++y)
                {
                    var line = rs;
                    for (int x = 0; x < w; ++x)
                    {
                        sOrg[y*w + x] = line[x] == '.' ? 0 : -1;
                    }
                }



                s = new int[h*w];
                Array.Copy(sOrg, s, s.Length);

                maxPos = FindStartPos();
                maxDistance = 0;
                do
                {
                    q = new Queue<int[]>();
                    s[Ofs(maxPos[0], maxPos[1])] = 1;
                    q.Enqueue(new int[2] { maxPos[0], maxPos[1] });
                    var currentDistance = maxDistance;
                    SolveMaze();
                    //DumpMaze();
                    if (maxDistance == currentDistance) break;
                    Array.Copy(sOrg,s,s.Length);
                } while (true);
                Wl(maxDistance-1);
            }

            private void DumpMaze()
            {
                var sb = new StringBuilder();
                for (int y = 0; y < h; ++y)
                {
                    for (int x = 0; x < w; ++x)
                    {
                        var val = s[y*w + x];
                        sb.Append(val >= 0 ? s[y*w + x].ToString("D2") : s[y*w + x].ToString("D"));
                    }
                    sb.AppendLine("");
                }
                Wl(sb.ToString());
                Wl($"currentDistance : {maxDistance}");
            }

            int Ofs(int x, int y)
            {
                return y*w + x;
            }

            bool IsInRange(int x, int y)
            {
                return 0 <= x && x < w && 0 <= y && y < h;
            }

            private void SolveMaze()
            {
                do
                {
                    //先にマスを塗ってからEnqueueした方がロスが少なそう。
                    var pos = q.Dequeue();
                    var nextDistance = s[Ofs(pos[0], pos[1])]+1;

                    var dir = new[] {new[] {1, 0}, new[] {-1, 0}, new[] {0, 1}, new[] {0, -1}};
                    for (int i = 0; i < dir.Length; ++i)
                    {
                        var next = new int[2];
                        next[0] = pos[0] + dir[i][0];
                        next[1] = pos[1] + dir[i][1];
                        if (!IsInRange(next[0], next[1])) continue;
                        if (s[Ofs(next[0], next[1])] != 0) continue;
                        s[Ofs(next[0], next[1])] = nextDistance;
                        if (nextDistance > maxDistance)
                        {
                            maxDistance = nextDistance;
                            maxPos[0] = next[0];
                            maxPos[1] = next[1];
                        }
                        q.Enqueue(next);
                    }

                } while (q.Count > 0);
            }

            private int[] FindStartPos()
            {
                var start = new int[2];
                for (int y = 0; y < h; ++y)
                {
                    for (int x = 0; x < w; ++x)
                    {
                        if (s[Ofs(x,y)] == 0)
                        {
                            start[0] = x;
                            start[1] = y;
                            return start;
                        }
                    }
                }
                throw new InvalidOperationException();
            }


            // ----------------------------------------------------------------------------
            static public void Swap<T>(ref T a, ref T b) { var tmp = a; a = b; b = tmp; }


            string Rl()
            {
                return Console.ReadLine();
            }
            void Wl(UInt64 val)
            {
                Console.WriteLine(val);
            }
            void Wl(Int64 val)
            {
                Console.WriteLine(val);
            }
            void Wl(uint val)
            {
                Console.WriteLine(val);
            }
            void Wl(int val)
            {
                Console.WriteLine(val);
            }
            void Wl(double val)
            {
                Console.WriteLine(val);
            }
            void Wl(string mes)
            {
                Console.WriteLine(mes);
            }
            public int Int()
            {
                return int.Parse(Console.ReadLine());
            }

            public int[] Ints(int subtract)
            {
                return Console.ReadLine().Split(' ').Select(s => int.Parse(s) - subtract).ToArray();
            }
            public Int64[] Int64s(Int64 subtract)
            {
                return Console.ReadLine().Split(' ').Select(s => Int64.Parse(s) - subtract).ToArray();
            }
            public UInt64[] UInt64s(UInt64 subtract)
            {
                return Console.ReadLine().Split(' ').Select(s => UInt64.Parse(s) - subtract).ToArray();
            }


        }



        static void Main(string[] args)
        {
            //Console.SetOut(new Printer(Console.OpenStandardOutput()) { AutoFlush = false });
            new Solver().Solve();
            //Console.Out.Flush();
        }
    }

    public class Printer : StreamWriter
    {
        public override IFormatProvider FormatProvider => CultureInfo.InvariantCulture;
        public Printer(Stream stream) : base(stream, new UTF8Encoding(false, true)) { }
    }

    public class StreamScanner
    {
        public StreamScanner(Stream stream) { str = stream; }

        public readonly Stream str;
        private readonly byte[] buf = new byte[1024];
        private int len, ptr;
        public bool isEof = false;

        private byte read()
        {
            if (isEof) return 0;
            if (ptr >= len)
            {
                ptr = 0;
                if ((len = str.Read(buf, 0, 1024)) <= 0)
                {
                    isEof = true;
                    return 0;
                }
            }
            return buf[ptr++];
        }

        public char Char()
        {
            byte b = 0;
            do b = read(); while ((b < 33 || 126 < b) && !isEof);
            return (char)b;
        }
        public string Scan()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b >= 33 && b <= 126; b = (char)read()) sb.Append(b);
            return sb.ToString();
        }
        public string ScanLine()
        {
            var sb = new StringBuilder();
            for (var b = Char(); b != '\n' && b != 0; b = (char)read()) if (b != '\r') sb.Append(b);
            return sb.ToString();
        }
        public long Long() { return isEof ? long.MinValue : long.Parse(Scan()); }
        public int Integer() { return isEof ? int.MinValue : int.Parse(Scan()); }
        public double Double() { return isEof ? double.NaN : double.Parse(Scan(), CultureInfo.InvariantCulture); }
    }

    struct ModInt
    {
        const int MOD = 1000000007;
        long Data;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public ModInt(long data) { if ((Data = data % MOD) < 0) Data += MOD; }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator long(ModInt modInt) => modInt.Data;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static implicit operator ModInt(long val) => new ModInt(val);
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator +(ModInt a, ModInt b)
        {
            long res = a.Data + b.Data;
            return new ModInt() { Data = res >= MOD ? res - MOD : res };
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator +(ModInt a, long b) => a.Data + b;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator -(ModInt a, ModInt b)
        {
            long res = a.Data - b.Data;
            return new ModInt() { Data = res < 0 ? res + MOD : res };
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator -(ModInt a, long b) => a.Data - b;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator *(ModInt a, ModInt b) => new ModInt() { Data = a.Data * b.Data % MOD };
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static ModInt operator /(ModInt a, ModInt b) => a.Data * GetInverse(b);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public override string ToString() => Data.ToString();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static long GetInverse(long a)
        {
            long div;
            long p = MOD;
            long x1 = 1, y1 = 0, x2 = 0, y2 = 1;
            while (true)
            {
                if (p == 1) return x2;
                div = a / p;
                x1 -= x2 * div;
                y1 -= y2 * div;
                a %= p;
                if (a == 1) return x1;
                div = p / a;
                x2 -= x1 * div;
                y2 -= y1 * div;
                p %= a;
            }
        }
    }

}