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# (Mono 4.6.2.0) (judge verdict: Time Limit Exceeded)



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ClassLibrary1
{
    public class ListNode
    {
        public int val;
        public ListNode next;
        public ListNode(int x) { val = x; }
    }


    public class Class1
    {
        static Dictionary<Tuple<long, long>, long> dic = new Dictionary<Tuple<long, long>, long>();

        static long mod = 1000000007;
        static long[] factorial = new long[100001];
        static long[] invFactorial = new long[100001];

        private static void calcFanctorial(long N)
        {
            factorial[0] = 1;
            for(int i=1; i< N+1; i++)
            {
                factorial[i] = factorial[i - 1] * i;
                factorial[i] %= mod;
            }
            invFactorial[N] = inv(factorial[N]);
            for (int i = (int)N; i > 0; i--)
            {
                invFactorial[i - 1] = invFactorial[i] * i % mod;
            }

        }

        static void Main(string[] args)
        {

            var AA = ReadLongArr();
            long H = AA[0];
            long W = AA[1];
            var input = ReadCharMatrix(H);
            var mtx = CreateIntMatrix(H, W);

            List<Edge> edges = new List<Edge>();
            List<int> points = new List<int>();

            int p = 1;
            for (int i = 0; i < H; i++)
            {
                for (int j = 0; j < W; j++)
                {
                    if (input[i][j] == '.')
                    {
                        mtx[i][j] = p;
                        points.Add(p);
                        p++;

                        if (i > 0)
                        {
                            if (mtx[i - 1][j] > 0)
                            {
                                edges.Add(new Edge { e1 = mtx[i - 1][j], e2 = mtx[i][j] });
                            }
                        }
                        if (j > 0)
                        {
                            if (mtx[i][j - 1] > 0)
                            {
                                edges.Add(new Edge { e1 = mtx[i][j - 1], e2 = mtx[i][j] });
                            }
                        }
                    }
                    else
                    {
                        mtx[i][j] = -1;
                    }
                }
            }


            var res = 0;
            foreach(var p1 in points)
            {
                added = new HashSet<int>();
                added.Add(p1);
                List<int> pp2 = new List<int>();
                pp2.Add(p1);
                var dist = recursive(pp2, 0, points.Count, edges);
                res = Math.Max(res, dist);
            }
            Console.WriteLine(res);

        }
        static HashSet<int> added = new HashSet<int>();

        private static int recursive(List<int> pp, int dist, int count, List<Edge> edges)
        {


            if (added.Count == count) return dist;
            List<int> pp2 = new List<int>();
            foreach (var px in pp)
            {
                foreach (var e in edges)
                {
                    var p2 = e.getOtherSide(px);
                    if (p2 > 0 && !pp.Contains(p2))
                    {
                        pp2.Add(p2);
                        added.Add(p2);
                    }
                }
            }
            if (pp2.Count == 0) return dist;

            return recursive(pp2, dist + 1, count, edges);
        }

        private class Edge
        {
            public int e1;
            public int e2;

            public bool Equals(int f1, int f2)
            {
                return ((e1 == f1) && (e2 == f2)) || ((e1 == f2) && (e2 == f1));
            }
            public int getOtherSide(int e)
            {
                if (e1 == e) return e2;
                if (e2 == e) return e1;
                return -1;
            }
        }

        private static long nCm(long n, long m)
        {
            if (n < m) return 0;

             return (factorial[n] * invFactorial[m] % mod) * invFactorial[n-m] % mod;
        }

        public static long pow(long a, long b, long mod)
        {
            a %= mod;

            if (b <= 0) return 1;
            var t = pow(a, b / 2, mod);
            if ((b & 1) == 0) return t * t % mod;
            return t * t % mod * a % mod;
        }

        public static long Lcm(long a, long b)
        {
            return a * b % mod * inv(Gcd(a, b)) % mod;
        }

        public static long Lcm(long[] a)
        {
            List<long> vect = new List<long>();
            long lcm = 1;
            for (int i = 0; i < a.Count(); i++)
            {
                var factor = a[i] / GcdVector(vect, a[i]);
                vect.Add(factor);
                lcm = lcm * factor % mod;
            }
            return lcm;
        }

        static long GcdVector(List<long> a, long b)
        {
            long ma = 1;
            for (int i = 0; i < a.Count; i++)
                ma = ma * a[i] % b;
            return Gcd(b, ma);
        }

        public static long Gcd(long a, long b)
        {
            if (a < b)
                // 引数を入替えて自分を呼び出す
                return Gcd(b, a);
            while (b != 0)
            {
                var remainder = a % b;
                a = b;
                b = remainder;
            }
            return a;
        }

        public static long pow(long a, long b) => pow(a, b, mod);
        public static long inv(long a) => pow(a, mod - 2);

        private static char[][] ReadCharMatrix(long h)
        {
            char[][] mtx = new char[h][];
            for(int i=0; i<h; i++)
            {
                var s = ReadString();
                mtx[i] = s.ToCharArray();
            }
            return mtx;
        }

        private static int[][] CreateIntMatrix(long h, long w)
        {
            int[][] mtx = new int[h][];
            for (int i = 0; i < h; i++)
            {
                mtx[i] = new int[w];
            }
            return mtx;
        }


        private static string ReadString()
        {
            return Console.ReadLine();
        }
        private static string[] ReadStringArr()
        {
            return Console.ReadLine().Split(' ');
        }
        private static long ReadLong()
        {
            return long.Parse(Console.ReadLine());
        }
        private static long[] ReadLongArr()
        {
            string[] s = ReadStringArr();
            long[] l = new long[s.Length];
            for(int i=0; i<l.Length; i++)
            {
                l[i] = long.Parse(s[i]);
            }

            return l;
        }
    }

}