#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define REP(i,n) for(int (i)=0;(i)<(n);++(i))
#define FOR(i,a,b) for(int (i)=(a);(i)<(b);++(i))
#define EACH(e,v) for(auto& e:v)
#define ALL(v) (v).begin(),(v).end()
#define SORT(v) sort(ALL(v))
#define RSORT(v) sort((v).rbegin(),(v).rend())
#define PERM(v) SORT(v);for(bool c##p=1;c##p;c##p=next_permutation(ALL(v)))
#define UNIQUE(v) SORT(v);(v).erase(unique(ALL(v)),(v).end())
template<typename A,typename B> inline bool chmax(A &a,const B &b){if(a<b){a=b;return 1;}return 0;}
template<typename A,typename B> inline bool chmin(A &a,const B &b){if(a>b){a=b;return 1;}return 0;}

const int MOD = (int)1e9 + 7;
const int INF = 1 << 28;
const ll INFF = 1LL << 62;

// 下にy, 右にx
enum {R, U, L, D};
const int dx[] = {1,  0, -1, 0};
const int dy[] = {0, -1,  0, 1};

/*
・Dinic
  > O(EV^2) [E:辺の数, V:頂点の数]
[備考] 最大流を求めるアルゴリズム.
      最大流は最小カットと一致する(最大フロー最小カット定理).
      「燃やす埋める問題」や「全ての頂点を二色に塗り分ける問題」などは最小カットに帰着できる.
[参考] http://yosupo.hatenablog.com/entry/2015/03/31/134336
[使用例]
Dinic<int> dnc(N);                // 頂点数Nのグラフを用意.
dnc.add_edge(from, to, cap);      // 頂点fromから頂点toへ容量capの有向辺を足す.
dnc.max_flow(s, t);               //
*/

template<typename T> struct Dinic {
  struct edge {
    int to;
    T cap;
    int rev;
  };

  vector< vector< edge > > graph;
  vector< T > min_cost;
  vector< int > iter;

  Dinic(int n) {
    graph.resize(n);
  }

  void add_edge(int from, int to, T cap) {
    graph[from].push_back((edge) {to, cap, (int) graph[  to].size()});
    graph[  to].push_back((edge) {from, 0, (int) graph[from].size() - 1});
  }

  bool bfs(int s, int t) {
    min_cost.assign(graph.size(), -1);
    queue<int> que;
    min_cost[s] = 0;
    que.push(s);
    while (!que.empty()) {
      int p = que.front();
      que.pop();
      for (auto &e : graph[p]) {
        if (e.cap > 0 && min_cost[e.to] == -1) {
          min_cost[e.to] = min_cost[p] + 1;
          que.push(e.to);
        }
      }
    }
    return (min_cost[t] != -1);
  }

  T dfs(int idx, const int t, T flow) {
    if (idx == t) return (flow);
    for (int &i = iter[idx]; i < graph[idx].size(); i++) {
      edge &e = graph[idx][i];
      if (e.cap > 0 && min_cost[idx] < min_cost[e.to]) {
        T d = dfs(e.to, t, min(flow, e.cap));
        if (d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return (d);
        }
      }
    }
    return (0);
  }

  T max_flow(int s, int t) {
    T flow = 0;
    while (bfs(s, t)) {
      iter.assign(graph.size(), 0);
      T f = 0;
      while ((f = dfs(s, t, INF)) > 0) {
        flow += f;
      }
    }
    return (flow);
  }
};

signed main() {

    int H, W;
    cin >> H >> W;

    vector<string> board(H);
    REP(i, H) cin >> board[i];

    pair<int, int> start, goal;

    vector<vector<int>> leaf_h(H), leaf_w(W);
    REP(h, H) REP(w, W) {
        if (board[h][w] == '.') continue;
        if (board[h][w] == 'S') start = make_pair(h, w);
        else if (board[h][w] == 'T')  goal = make_pair(h, w);
        else {
            leaf_h[h].emplace_back(w);
            leaf_w[w].emplace_back(h);
        }
    }

    if (start.first == goal.first || start.second == goal.second) {
        cout << -1 << endl;
        return 0;
    }

    Dinic<ll> dnc(1010);
    
    const int S = 998;
    const int T = 999;

    REP(h, H) {
        EACH(w, leaf_h[h]) {
            dnc.add_edge(h, w + H, 1);
            dnc.add_edge(w + H, h, 1);
        }
    }

    dnc.add_edge(S, start.first, INF);
    dnc.add_edge(S, start.second + H, INF);
    dnc.add_edge(goal.first, T, INF);
    dnc.add_edge(goal.second + H, T, INF);

    cout << dnc.max_flow(S, T) << endl;

}

Measured memory_bytes: 1664