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.Numerics;
using System.Runtime.CompilerServices;
using System.Diagnostics;
using ll=System.Int64;
using static Contest_D.MyIO;



public class Contest_D
{
	static void swap1<T>(ref T a, ref T b) { T t = a; a = b; b = t; }
	static void swap2<T>(ref T a, ref T b) where T : IComparable { if (a.CompareTo(b)==1) swap1(ref a, ref b); }  // b の方が小さければ交換
	static bool chmin<T>(ref T a, T b) where T : IComparable { if (a.CompareTo(b)== 1) { a = b; return true; } return false; }  // b の方が小さければ a を更新
	static bool chmax<T>(ref T a, T b) where T : IComparable { if (a.CompareTo(b)==-1) { a = b; return true; } return false; }  // b の方が大きければ a を更新
	static bool inside(long i, long n) => (0<=i&&i<n);
	static bool inside(long x, long y, long w, long h) => (inside(x,w)&&inside(y,h));
	static T min<T>(params T[] a) where T : IComparable => a.Min();
	static T max<T>(params T[] a) where T : IComparable => a.Max();
	static long mod(long a, long m) { var v = a%m; return (v<0?v+m:v); }
	static T[][] init<T>(long len1,long len2,T val) where T : struct { T[][] m = new T[len1][]; for (int i=0;i<m.Length;i++) m[i] = Enumerable.Repeat(val,(int)len2).ToArray(); return m; }
	static T[][][] init<T>(long len1,long len2,long len3,T val) where T : struct { T[][][] m = new T[len1][][]; for (int i=0;i<m.Length;i++) m[i] = init(len2,len3,val); return m; }
	public const long MOD1 = 1000000007; // 10^9+7
	public const double EPS1 = 1e-8;
	public const long INF1 = 1000000000000000;  // 10^15

	public static void Main() {
		checked{
			long  h, w;
			MyIO.RM(out h, out w);
			string[] s;
			RL(h,out s);


			ll ans = 0;
			List< ll >[] gl = new List<ll>[h*w];
			for (int sx = 0; sx < h; sx++)
			{
				for (int sy = 0; sy < w; sy++)
				{
					ll k=sx*w+sy;
					gl[k] = new List<ll>();
					if(s[sx][sy]=='.') {
						if(sx<h-1&&s[sx+1][sy]=='.') gl[k].Add((sx+1)*w+sy);
						if(0<sx&&s[sx-1][sy]=='.') gl[k].Add((sx-1)*w+sy);
						if(sy<w-1&&s[sx][sy+1]=='.') gl[k].Add(sx*w+sy+1);
						if(0<sy&&s[sx][sy-1]=='.') gl[k].Add(sx*w+sy-1);
					}
				}
			}
			for (int sx = 0; sx < h; sx++)
			{
				for (int sy = 0; sy < w; sy++)
				{
					ll k=sx*w+sy;
					if(s[sx][sy]=='.') chmax(ref ans, Search(h*w,k, gl));
				}
			}
			MyIO.WM(ans);
		}
	}


	public class modque<T>{
		int t;
		Queue<T> q;
		Stack<T> s;
		Action<T> fin;
		Func<T> fout;
		Func<int> fcnt;
		public modque(int type, int size){
			t = type;
			if(t==1) {
				s = new Stack<T>();
				fin = s.Push;
				fout = s.Pop;
				fcnt = () => s.Count;
			}
			else {
				q = new Queue<T>();
				fin = q.Enqueue;
				fout = q.Dequeue;
				fcnt = () => q.Count;
			}
		}
		public void In(T a) => fin(a);
		public T Out() => fout();
		public int Count() => fcnt();
	}

    public static long Search(long N, long start, IList<IList<long>> map){
		long count = 0;
        int stype = 2;  // 1:DFS 2:BFS
        modque<VT<long,object>> container = new modque<VT<long,object>>(stype, 2*(int)N);
        container.In(new VT<ll, object>(start,0));
        bool[] visited = new bool[N]; 
        while(0<container.Count()){
            VT<long,object> now;
            now = container.Out();
            visited[now.Item1]=true;
			int nc = (int)now.Item2;
			if(count<nc) count = nc;
            foreach (var e in map[(int)now.Item1]) {
                if(visited[e]) continue;
                container.In(new VT<ll, object>(e,nc+1));
            }
        }
		return count;
    }


public class Deque<T> {
    int dx;
    T[] buf;
    int mask;

    /// <summary>
    ///<see cref="Deque{T}"/> に格納されている要素の数を取得します．
    /// </summary>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public int Count { get; private set; }
    
    /// <summary>
    /// 空であって，既定の初期容量を備えた <see cref="Deque{T}"/> クラスの新しいインスタンスを初期化します．
    /// </summary>
    public Deque() : this(8) { }
    
    /// <summary>
    /// 空であって，指定の初期容量を備えた <see cref="Deque{T}"/> クラスの新しいインスタンスを初期化します．
    /// </summary>
    /// <param name="capacity">作成したインスタンスが格納できる要素数の初期値．2 べきの値にしてください．</param>
    public Deque(int capacity) {
        int nbase = 1;  // 追加
		while((1 << nbase) < capacity) nbase++;  // 追加
		capacity = 1 << nbase;  // 追加
        Debug.Assert(capacity == (capacity & -capacity));
        mask = capacity - 1;
        buf = new T[capacity];
    }
    
    /// <summary>
    /// 指定したインデックスにある要素を取得または設定します．
    /// </summary>
    /// <param name="index">取得または設定する要素の，0-inexed での番号．</param>
    /// <returns>指定したインデックス位置にある要素</returns>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public T this[int index] {
        get {
            Debug.Assert(0 <= index && index < Count);
            return buf[(dx + index) & mask];
        }
        set {
            Debug.Assert(0 <= index && index < Count);
            buf[(dx + index) & mask] = value;
        }
    }

    /// <summary>
    /// <see cref="Deque{T}"/> の先頭に要素を追加します．
    /// </summary>
    /// <param name="item">追加する要素</param>
    /// <remarks>この操作はならし計算量 O(1) で実行されます．</remarks>
    public void PushFront(T item) {
        if (Count == buf.Length) extend();
        dx = (dx + buf.Length - 1) & mask;
        buf[dx] = item;
        Count++;
    }

    /// <summary>
    /// <see cref="Deque{T}"/> の先頭から要素を削除し，返します．
    /// </summary>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public T PopFront() {
        Debug.Assert(Count > 0);
        var ret = buf[dx];  // 修正
		dx = (dx + 1) & mask;  // 修正
        Count--;
        return ret;
    }

    /// <summary>
    /// <see cref="Deque{T}"/> の末尾に要素を追加します．
    /// </summary>
    /// <param name="item">追加する要素</param>
    /// <remarks>この操作はならし計算量 O(1) で実行されます．</remarks>
    public void PushBack(T item) {
        if (Count == buf.Length) extend();
        buf[(dx + Count++) & mask] = item;
    }
    
    /// <summary>
    /// <see cref="Deque{T}"/> の末尾から要素を削除し，返します．
    /// </summary>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public T PopBack() {
        Debug.Assert(Count > 0);
        var ret = buf[(dx + --Count) & mask];
        return ret;
    }

    /// <summary>
    /// <see cref="Deque{T}"/> の末尾の要素を返します．
    /// </summary>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public T Last() {
        Debug.Assert(Count > 0);
        return buf[(dx + Count - 1) & mask];
    }
    
    /// <summary>
    /// <see cref="Deque{T}"/> の先頭の要素を返します．
    /// </summary>
    /// <remarks>この操作は計算量 O(1) で実行されます．</remarks>
    public T First() {
        Debug.Assert(Count > 0);
        return buf[dx];
    }

    void extend() {
        var nbuf = new T[buf.Length * 2];
        for (int i = 0; i < buf.Length; i++)
            nbuf[i] = buf[(dx + i) & mask];
        mask = mask * 2 + 1;
        dx = 0;
        buf = nbuf;
    }
    
    /// <summary>
    /// デックを空にします．
    /// </summary>
    /// <remarks>この操作は O(1) で実行されます．</remarks>
    public void Clear() { Count = 0; }
    
    /// <summary>
    /// <see cref="Deque{T}"/> 内に要素が存在するかどうかを調べます．
    /// </summary>
    /// <returns>要素が存在するならば true，そうでなければ false</returns>
    /// <remarks>この操作は O(1) で実行されます．</remarks>
    public bool Any() { return Count != 0; }
    
    /// <summary>
    /// 指定した位置に要素を挿入します．
    /// </summary>
    /// <param name="item">追加したい要素</param>
    /// <param name="index">追加したい位置の 0-indexed での番号</param>
    /// <remarks>この操作は最悪計算量 O(N) で実行されます．</remarks>
    public void Insert(int index, T item) {
        Debug.Assert(0 <= index && index <= Count);
        PushFront(item);
        for (int i = 0; i < index; i++)
            this[i] = this[i + 1];
        this[index] = item;
    }
    
    /// <summary>
    /// 指定した位置にある要素を削除し，返します．
    /// </summary>
    /// <param name="index">削除したい位置の 0-indexed での番号</param>
    /// <remarks>この操作は最悪計算量 O(N) で実行されます．</remarks>
    public T RemoveAt(int index) {
        Debug.Assert(0 <= index && index < Count);
        var ret = this[index];
        for (int i = index; i > 0; i--)
            this[i] = this[i - 1];
        PopFront();
        return ret;
    }

    /// <summary>
    /// <see cref="Deque{T}"/> 内にある要素の一覧を返します．
    /// </summary>
    /// <returns><see cref="Deque{T}"/> 内にある要素の一覧</returns>
    /// <remarks>この操作は O(N) で実行されます．</remarks>
    public T[] Items {
        get {

            var ret = new T[Count];
            for (int i = 0; i < Count; i++)
                ret[i] = this[i];
            return ret;
        }
    }
}






#region MyIO

public struct VT<T,U>
{
	public T Item1; public U Item2;
    public VT(T a,U b) { Item1 = a; Item2 = b; }
}
public struct VT<T,U,V>
{
	public T Item1; public U Item2; public V Item3;
    public VT(T a,U b,V c) { Item1 = a; Item2 = b; Item3 = c; }
}
public struct VT<T,U,V,W>
{
	public T Item1; public U Item2; public V Item3; public W Item4;
    public VT(T a,U b,V c,W d) { Item1 = a; Item2 = b; Item3 = c; Item4 = d; }
}

public static class MyIO
{
	class Prt : System.IO.StreamWriter
	{
		public override IFormatProvider FormatProvider { get { return System.Globalization.CultureInfo.InvariantCulture; } }
		public Prt(System.IO.Stream s) : base(s,new UTF8Encoding(false,true)) {}
		public Prt(System.IO.Stream s,Encoding e) : base(s,e) {}
	}
	
	static char[] sp = new char[] {' '};
	[MethodImpl(256)]
	static bool eq<T,U>() => typeof(T).Equals(typeof(U));
	[MethodImpl(256)]
	static T ct<T,U>(U a) => (T)Convert.ChangeType(a,typeof(T));
	static T cv<T>(string s) =>
		eq<T,int>()    ? ct<T,int>(int.Parse(s))
	  : eq<T,long>()   ? ct<T,long>(long.Parse(s))
	  : eq<T,double>() ? ct<T,double>(double.Parse(s,System.Globalization.CultureInfo.InvariantCulture))
	  : eq<T,char>()   ? ct<T,char>(s[0])
					   : ct<T,string>(s);
	public static string[] RM<T>(out T a) {
		var z = Console.ReadLine().Split(sp,StringSplitOptions.RemoveEmptyEntries); 
		a = cv<T>(z[0]);
		return z;
	}
	public static string[] RM<T,U>(out T a,out U b) {
		var z = RM<T>(out a); 
        b = cv<U>(z[1]);
		return z;
	}
	public static string[] RM<T,U,V>(out T a,out U b,out V c) {
		var z = RM<T,U>(out a,out b); 
        c = cv<V>(z[2]);
		return z;
	}
	public static string[] RM<T,U,V,W>(out T a,out U b,out V c,out W d) {
		var z = RM<T,U,V>(out a,out b,out c); 
        d = cv<W>(z[3]);
		return z;
	}
	public static string[] RM<T,U,V,W,X>(out T a,out U b,out V c,out W d,out X e) {
		var z = RM<T,U,V,W>(out a,out b,out c,out d); 
        e = cv<X>(z[4]);
		return z;
	}
	public static string[] RM<T,U,V,W,X,Y>(out T a,out U b,out V c,out W d,out X e,out Y f) {
		var z = RM<T,U,V,W,X>(out a,out b,out c,out d,out e); 
        f = cv<Y>(z[5]);
		return z;
	}
	public static string[] RA<T>(out T[] a) {		
		var z = Console.ReadLine().Split(sp,StringSplitOptions.RemoveEmptyEntries);
		a = z.Select(cv<T>).ToArray();
		return z;
	}
	public static string[][] RL<T>(long n,out T[] a) {
		a = new T[n];
		var y = new string[n][];
		for(int i=0;i<n;i++) y[i] = RM(out a[i]);
		return y;
	}
	public static string[][] RL<T,U>(long n,out VT<T,U>[] a) {
		a = new VT<T,U>[n];
		var y = new string[n][];
		for(int i=0;i<n;i++) {
			T o; U p;
			y[i] = RM(out o,out p);
			a[i] = new VT<T,U>(o,p);
		}
		return y;
	}
	public static string[][] RL<T,U,V>(long n,out VT<T,U,V>[] a) {
		a = new VT<T,U,V>[n];
		var y = new string[n][];
		for(int i=0;i<n;i++) {
			T o; U p; V q;
			y[i] = RM(out o,out p,out q);
			a[i] = new VT<T,U,V>(o,p,q);
		}
		return y;
	}
	public static string[][] RL<T,U,V,W>(long n,out VT<T,U,V,W>[] a) {
		a = new VT<T,U,V,W>[n];
		var y = new string[n][];
		for(int i=0;i<n;i++) {
			T o; U p; V q; W r;
			y[i] = RM(out o,out p,out q,out r);
			a[i] = new VT<T,U,V,W>(o,p,q,r);
		}
		return y;
	}
	public static string[][] RX<T>(long n,out T[][] a) {
		a = new T[n][];
		var y = new string[n][];
		for(int i=0;i<n;i++) y[i] = RA(out a[i]);
		return y;
	}

	static void wwp(Action act){
		var s = new Prt(Console.OpenStandardOutput()){AutoFlush = false};
		Console.SetOut(s);
		act();
		Console.Out.Flush();
		s.AutoFlush = true;
		Console.SetOut(s);
	}
	[MethodImpl(256)]
	static string wfm(Type t) =>t.Equals(typeof(double)) ? "{0:F10}" : "{0}";
	public static void WM(params object[] a) {
		wwp(()=>{
			for(int i=0;i<a.Length;i++) {
				var f = wfm(a[i].GetType()) + ((i<a.Length-1) ? " " : Environment.NewLine);
				Console.Write(f,a[i]);
			}
		});
	}
	public static void WA<T>(IList<T> a) {
		wwp(()=>{
			var f = wfm(typeof(T));
			var g = f + " ";
			var h = f + Environment.NewLine;
			for(int i=0;i<a.Count;i++) Console.Write(((i<a.Count-1) ? g : h),a[i]);
		});
	}
	public static void WL<T>(IList<T> a) {
		wwp(()=>{
			var f = wfm(typeof(T)) + Environment.NewLine;
			foreach(T x in a) Console.Write(f,x);
		});
	}


}

#endregion


}