Problem:
Score : 800 points

Problem Statement

There is a pond with a rectangular shape.
The pond is divided into a grid with H rows and W columns of squares.
We will denote the square at the i-th row from the top and j-th column from the left by (i,\ j).

Some of the squares in the pond contains a lotus leaf floating on the water.
On one of those leaves, S, there is a frog trying to get to another leaf T.
The state of square (i,\ j) is given to you by a character a_{ij}, as follows:

. : A square without a leaf.

o : A square with a leaf floating on the water.

S : A square with the leaf S.

T : A square with the leaf T.

The frog will repeatedly perform the following action to get to the leaf T: "jump to a leaf that is in the same row or the same column as the leaf where the frog is currently located."

Snuke is trying to remove some of the leaves, other than S and T, so that the frog cannot get to the leaf T.
Determine whether this objective is achievable. If it is achievable, find the minimum necessary number of leaves to remove.

Constraints

2 ≤ H, W ≤ 100

a_{ij} is ., o, S or T.

There is exactly one S among a_{ij}.

There is exactly one T among a_{ij}.

Input

Input is given from Standard Input in the following format:

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

Output

If the objective is achievable, print the minimum necessary number of leaves to remove.
Otherwise, print -1 instead.

Sample Input 1

3 3
S.o
.o.
o.T

Sample Output 1

2

Remove the upper-right and lower-left leaves.

Sample Input 2

3 4
S...
.oo.
...T

Sample Output 2

0

Sample Input 3

4 3
.S.
.o.
.o.
.T.

Sample Output 3

-1

Sample Input 4

10 10
.o...o..o.
....o.....
....oo.oo.
..oooo..o.
....oo....
..o..o....
o..o....So
o....T....
....o.....
........oo

Sample Output 4

5

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using CompLib.Util;
using System;
using System.Collections.Generic;
using CompLib.Graph.Flow;

public class Program
{
    private int H, W;
    private char[][] A;

    public void Solve()
    {
        var sc = new Scanner();
        H = sc.NextInt();
        W = sc.NextInt();
        A = new char[H][];
        for (int i = 0; i < H; i++)
        {
            A[i] = sc.NextCharArray();
        }

        int s = -1;
        int t = -1;
        var minCut = new MaxFlow(H * W * 2);
        for (int i = 0; i < H; i++)
        {
            for (int j = 0; j < W; j++)
            {
                int p = i * W + j;
                switch (A[i][j])
                {
                    case 'S':
                        s = p;
                        // 横
                        for (int x = 0; x < W; x++)
                        {
                            if (x == j) continue;
                            switch (A[i][x])
                            {
                                case 'T':
                                    Console.WriteLine("-1");
                                    return;
                                case 'o':
                                    minCut.AddDirectedEdge(p + H * W, i * W + x, int.MaxValue);
                                    break;
                            }
                        }

                        // 縦
                        for (int y = 0; y < H; y++)
                        {
                            if (y == i) continue;
                            switch (A[y][j])
                            {
                                case 'T':
                                    Console.WriteLine("-1");
                                    return;
                                case 'o':
                                    minCut.AddDirectedEdge(p + H * W, y * W + j, int.MaxValue);
                                    break;
                            }
                        }

                        break;
                    case 'T':
                        t = p;
                        break;
                    case 'o':
                        for (int x = 0; x < W; x++)
                        {
                            if (x == j) continue;
                            if (A[i][x] == 'o' || A[i][x] == 'T')
                            {
                                minCut.AddDirectedEdge(p + H * W, i * W + x, int.MaxValue);
                            }
                        }

                        for (int y = 0; y < H; y++)
                        {
                            if (y == i) continue;
                            if (A[y][j] == 'o' || A[y][j] == 'T')
                            {
                                minCut.AddDirectedEdge(p + H * W, y * W + j, int.MaxValue);
                            }
                        }

                        minCut.AddDirectedEdge(p, p + H * W, 1);
                        break;
                }
            }
        }

        Console.WriteLine(minCut.Execute(s + H * W, t));
    }

    public static void Main(string[] args) => new Program().Solve();
}


namespace CompLib.Graph.Flow
{
    using C = System.Int64;

    #region Max Flow

    /// <summary>
    /// 辺の追加を行い，最大流を求めることが可能なグラフです．
    /// </summary>
    public class MaxFlow
    {
        readonly List<Edge>[] G;
        readonly int[] lv, iter;

        /// <summary>
        /// 頂点数 <paramref name="V"/> で辺が存在しないグラフを構築します．
        /// </summary>
        /// <param name="V">頂点の数</param>
        /// <remarks>この操作は O(<paramref name="V"/>) で実行されます．</remarks>
        public MaxFlow(int V)
        {
            G = new List<Edge>[V];
            lv = new int[V];
            iter = new int[V];
            for (int i = 0; i < G.Length; i++)
                G[i] = new List<Edge>();
        }

        /// <summary>
        /// 頂点 <paramref name="from"/> から頂点 <paramref name="to"/> への容量 <paramref name="cap"/> の有向辺を追加します．
        /// </summary>
        /// <param name="from">始点となる頂点の 0-indexed での番号</param>
        /// <param name="to">終点となる頂点の 0-indexed での番号</param>
        /// <param name="cap">辺の容量</param>
        /// <remarks>この操作は O(1) で実行されます．</remarks>
        public void AddDirectedEdge(int from, int to, C cap)
        {
            addEdge(from, to, cap, 0);
        }

        /// <summary>
        /// 頂点 <paramref name="from"/> から頂点 <paramref name="to"/> への容量 <paramref name="cap"/> の無向辺を追加します．
        /// </summary>
        /// <param name="from">始点となる頂点の 0-indexed での番号</param>
        /// <param name="to">終点となる頂点の 0-indexed での番号</param>
        /// <param name="cap">辺の容量</param>
        /// <remarks>この操作は O(1) で実行されます．</remarks>
        public void AddUndirectedEdge(int from, int to, C cap)
        {
            addEdge(from, to, cap, cap);
        }

        void addEdge(int f, int t, C c1, C c2)
        {
            var a = new Edge(t, c1);
            var b = new Edge(f, c2);
            Edge.Link(a, b);
            G[f].Add(a);
            G[t].Add(b);
        }


        /// <summary>
        /// 頂点 <paramref name="src"/> から頂点 <paramref name="sink"/> へ最大で流量 <paramref name="f"/> だけフローを流します．
        /// </summary>
        /// <param name="src">ソースとなる頂点の 0-indexed での番号</param>
        /// <param name="sink">シンクとなる頂点の 0-indexed での番号</param>
        /// <param name="f">ソースからシンクへと流す最大の容量．-1を指定した場合，最大流を求める．</param>
        /// <remarks>この操作はDinic法に基づき，最悪計算量 O(EV^2) で実行されます．Vは頂点の数，Eは辺の数ｗ表します．</remarks>
        public C Execute(int src, int sink, C f = -1)
        {
            C flow = 0;
            if (f < 0) f = C.MaxValue;
            while (f > 0)
            {
                bfs(src);
                if (lv[sink] == 0) return flow;
                Array.Clear(iter, 0, iter.Length);
                C df;
                while ((df = dfs(src, sink, f)) > 0)
                {
                    flow += df;
                    f -= df;
                }
            }

            return flow;
        }

        void bfs(int s)
        {
            Array.Clear(lv, 0, lv.Length);
            var q = new Queue<int>();
            lv[s] = 1;
            q.Enqueue(s);
            while (q.Count > 0)
            {
                var v = q.Dequeue();
                foreach (var e in G[v])
                    if (e.Cap > 0 && lv[e.To] == 0)
                    {
                        lv[e.To] = lv[v] + 1;
                        q.Enqueue(e.To);
                    }
            }
        }

        C dfs(int v, int t, C f)
        {
            if (v == t) return f;
            C ret = 0;
            for (; iter[v] < G[v].Count; iter[v]++)
            {
                var e = G[v][iter[v]];
                if (e.Cap <= 0 || lv[v] >= lv[e.To]) continue;
                C df = dfs(e.To, t, Math.Min(f, e.Cap));
                if (df <= 0) continue;
                e.Cap -= df;
                e.Rev.Cap += df;
                ret += df;
                f -= df;
                if (f == 0) break;
            }

            return ret;
        }

        class Edge
        {
            public static void Link(Edge e1, Edge e2)
            {
                e1.Rev = e2;
                e2.Rev = e1;
            }

            public int To { get; private set; }
            public Edge Rev { get; private set; }
            public C Cap { get; set; }

            public Edge(int t, C c)
            {
                To = t;
                Cap = c;
            }

            public override string ToString()
            {
                return string.Format("to: {0}, cap: {1}", To, Cap);
            }
        }
    }

    #endregion
}


namespace CompLib.Util
{
    using System;
    using System.Linq;

    class Scanner
    {
        private string[] _line;
        private int _index;
        private const char Separator = ' ';

        public Scanner()
        {
            _line = new string[0];
            _index = 0;
        }

        public string Next()
        {
            while (_index >= _line.Length)
            {
                _line = Console.ReadLine().Split(Separator);
                _index = 0;
            }

            return _line[_index++];
        }

        public int NextInt() => int.Parse(Next());
        public long NextLong() => long.Parse(Next());
        public double NextDouble() => double.Parse(Next());
        public decimal NextDecimal() => decimal.Parse(Next());
        public char NextChar() => Next()[0];
        public char[] NextCharArray() => Next().ToCharArray();

        public string[] Array()
        {
            _line = Console.ReadLine().Split(Separator);
            _index = _line.Length;
            return _line;
        }

        public int[] IntArray() => Array().Select(int.Parse).ToArray();
        public long[] LongArray() => Array().Select(long.Parse).ToArray();
        public double[] DoubleArray() => Array().Select(double.Parse).ToArray();
        public decimal[] DecimalArray() => Array().Select(decimal.Parse).ToArray();
    }
}