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: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using static System.Console;
using static System.Math;
 
public class Hello{
    static public int mod = 1000000007;
    public static void Main(){
        // 方針
        // 幅優先全探索
        int[] n = inta();
        int nowplace = n[0]*n[1]-1;
        char[,] map = new char[n[0],n[1]];
        for(int i=0;i<n[0];i++){
            string temp = rstr();
            for(int j=0;j<n[1];j++){
                map[i,j] = temp[j];
            }
        }
        int[] dt = new int[]{1,0,-1,0};
        int[] dy = new int[]{0,1,0,-1};
        
        int ans = 0;
        while(nowplace >= 0){
            int y = nowplace % n[1];
            int t = nowplace / n[1];
            if(map[t,y] == '#'){
                nowplace--;
                continue;
            }
            int[,] length = new int[n[0],n[1]];
            for(int i=0;i<n[0];i++){
                for(int j=0;j<n[1];j++){
                    length[i,j] = 999999999;
                }
            }
            length[t,y] = 0;
            var queue = new Queue<int>();
            queue.Enqueue(t);
            queue.Enqueue(y);
            bool[,] passed = new bool[n[0],n[1]];
            passed[t,y] = true;
            
            int max = 0;
            while(queue.Count > 0){
                int nowt = queue.Dequeue();
                int nowy = queue.Dequeue();
                for(int i=0;i<4;i++){
                    int movet = nowt+dt[i];
                    int movey = nowy+dy[i];
                    if(0 <= movet && movet < n[0] && 0 <= movey && movey < n[1]){
                        if(map[movet,movey] == '#') continue;
                        if(passed[movet,movey] == false){
                            queue.Enqueue(movet);
                            queue.Enqueue(movey);
                            passed[movet,movey] = true;
                            length[movet,movey] = length[nowt,nowy]+1;
                            max = Max(length[movet,movey],max);
                        }
                    }
                }
            }
            ans = Max(ans,max);
            nowplace--;
        }
        WriteLine(ans);
        
        
        
        
    }
    static void unionfind(ref int[] uni,int a,int b){
        var memo = new List<int>();
        memo.Add(a);
        memo.Add(b);
        int min = Min(a,b);
        while(uni[a] != a){
            a = uni[a];
            memo.Add(a);
        }
        while(uni[b] != b){
            b = uni[b];
            memo.Add(b);
        }
        min = Min(min,a);
        min = Min(min,b);
        foreach(var k in memo){
            uni[k] = min;
        }
    }
    static int unionfind2(ref int[] uni,int a){
        var memo = new List<int>();
        memo.Add(a);
        while(uni[a] != a){
            a = uni[a];
            memo.Add(a);
        }
        foreach(var k in memo){
            uni[k] = a;
        }
        return a;
    }
    static int binarysearchd(int[] a,int b){
        int leng = a.Length;
        int min = 0;
        int max = leng-1;
        while(max - min > 1){
            int mid = (min+max)/2;
            if(a[mid] < b){
                min = mid;
            }else{
                max = mid;
            }
        }
        if(a[0] >= b){
            return 0;
        }else if(a[leng-1] < b){
            return leng;
        }else{
            if(a[max] < b){
                return max+1;
            }
            return min+1;
        }
    }
    static int binarysearchu(int[] a,int b){
        int leng = a.Length;
        int min = 0;
        int max = leng-1;
        while(max - min > 1){
            int mid = (min+max)/2;
            if(a[mid] < b){
                min = mid;
            }else{
                max = mid;
            }
        }
        if(a[0] > b){
            return leng;
        }else if(a[leng-1] <= b){
            return 0;
        }else{
            if(a[max] <= b){
                return leng-(max+1);
            }
            return leng-(min+1);
        }
    }
    // 1からaまでの数字並べ替え全通り返すやつ
    static List<string> permutation(int a){var list = new List<string>();if(a == 1){list.Add("1");return list;}else{foreach(var k in permutation(a-1)){var ch = k.ToCharArray();for(int i=0;i<=ch.Length;i++){string intemp = "";if(i == 0){intemp += a.ToString();}for(int j=0;j<ch.Length;j++){intemp += ch[j].ToString();if(i == j+1){intemp += a.ToString();}}list.Add(intemp);}}}return list;}
    static void swap(ref int a,ref int b){int temp = a;a= b;b = temp;}
    static void charswap(ref char a,ref char b){char temp = a;a= b;b = temp;}
    static int ncr(int n,int r){r = Min(r,n-r);long nn = 1;for(int i=n-r+1;i<=n;i++){nn = nn*i%mod;}long rr = 1;for(int i=1;i<=r;i++){rr = rr*i%mod;}rr = square((int)rr,mod-2);nn = nn * rr %mod;return (int)nn;}
    // a^b mod
    static int square(int a,int b){string binary = Convert.ToString(b,2);int bileng = binary.Length;long a_power = a;long value = 1;for(int i=bileng-1;i>=0;i--){if(binary[i] == '1'){value = value*a_power%mod;}a_power = a_power*a_power%mod;}return (int)value;}
    static int square2(int a,int b){long output = 1;var list = new List<long>();int sh = 1;long n = a;list.Add(a);while(sh < b){sh *= 2;n = n*n%mod;list.Add(n);}for(int i=list.Count-1;i>=0;i--){if(b > sh){b -= sh;sh /= 2;output = output*list[i]%mod;}}return (int)output;}
    //各種読取
    static string rstr(){ return ReadLine(); }
    static int rint(){ return int.Parse(ReadLine()); }
    static long rlong(){ return long.Parse(ReadLine()); }
    static string[] stra(){ return ReadLine().Split(' '); }
    static char[] chara(){ string[] a=stra();string b="";for(int i=0;i<a.Length;i++){b+=a[i];}return b.ToCharArray();}
    static int[] inta(){ string[] read_str_array = ReadLine().Split(' '); int[] return_int_array = new int[read_str_array.Length]; for(int countup_i=0;countup_i<read_str_array.Length;countup_i++){ return_int_array[countup_i] = int.Parse(read_str_array[countup_i]); } return return_int_array; }
    static int[,] inta2(int num_array,int in_array){ int[,] int_array2 = new int[num_array,in_array]; for(int i=0;i<num_array;i++){ int[] temp_array = inta(); for(int j=0;j<in_array;j++){ int_array2[i,j] = temp_array[j]; } } return int_array2; }
    static long[] longa(){ string[] read_str_array = ReadLine().Split(' '); long[] return_long_array = new long[read_str_array.Length]; for(long countup_i=0;countup_i<read_str_array.Length;countup_i++){ return_long_array[countup_i] = long.Parse(read_str_array[countup_i]); } return return_long_array; }
    static double[] doublea(){ string[] read_str_array = ReadLine().Split(' '); double[] return_double_array = new double[read_str_array.Length]; for(long countup_i=0;countup_i<read_str_array.Length;countup_i++){ return_double_array[countup_i] = long.Parse(read_str_array[countup_i]); } return return_double_array; }
    // -----------------------------
    static long divideup(long divided,long divid){ long temp_divide = divided/divid; if(divided % divid > 0){ temp_divide++; } return temp_divide; }
    static long GCD(long a,long b){ if(a < b){ long temp = a; a = b; b = temp; } if(a % b == 0){ return b; } else{ long temp = b; b = a%b; a = temp; return GCD(a,b); } }
    static long LCM(long a,long b){ return a * b / GCD(a,b); }
}


//知見
// (string) hogestr -> (char[]) hoge
    // char hoge = hogestr.ToCharArray();
// (char[]) hoge -> (string) hogestr
    // string hoge = new string(hoge);
// Hashtable ×  Dictionary ○
// Dictionary hoge<string,int>
    // hoge.ContainsKey(string) -> return boolean
    // hoge[string] -> return int
    // hoge[int] -> CE
// Dictionary hoge<int1,int2>
    // hoge<int1,int2>: hoge[int1] -> return int2
    // KeyValuePair<int,int> k <-> k.Key == int1 / k.Value == int2
// SortedDictionary() > SortedList() ???
// キュー　-> 幅優先 ???
    // var queue = new Queue<int>(); queue.Enqueue() queue.Dequeue()
// スタック -> 深さ優先 ???
    // var stack = new Stack<int>(); stack.Push(hoge) stack.Pop() stackPeek() stack.Count
// if (list?.Count > 0) リストが空でもnullでもない
// ソート
    // list.Sort(StringComparer.Ordinal); listの(辞書順?)ソート
        // StringComparer.Ordinal とは
    // Array.Sort(list1,list2);
// 出力
    // foreach(var a int list){ WriteLine(a); } より
        // WriteLine(string.Join("\n", list)); が速い
    //var sw = new StreamWriter(Console.OpenStandardOutput()){AutoFlush = false};
    //    Console.SetOut(sw);
    //    foreach(var k in list[num-1]){
    //        WriteLine(k);
    //    }
    //    Console.Out.Flush();
// 未知
    // 最小費用流