#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <functional>
using namespace std;

#define rep(i,a,n) for(int (i)=(a); (i)<(n); (i)++)
#define repq(i,a,n) for(int (i)=(a); (i)<=(n); (i)++)
#define repr(i,a,n) for(int (i)=(a); (i)>=(n); (i)--)
#define all(v) begin(v), end(v)
#define pb(a) push_back(a)
#define fr first
#define sc second
#define INF 2000000000
#define int long long int

#define X real()
#define Y imag()
#define EPS (1e-10)
#define EQ(a,b) (abs((a) - (b)) < EPS)
#define EQV(a,b) ( EQ((a).X, (b).X) && EQ((a).Y, (b).Y) )
#define LE(n, m) ((n) < (m) + EPS)
#define LEQ(n, m) ((n) <= (m) + EPS)
#define GE(n, m) ((n) + EPS > (m))
#define GEQ(n, m) ((n) + EPS >= (m))

typedef vector<int> VI;
typedef vector<VI> MAT;
typedef pair<int, int> pii;
typedef long long ll;

typedef complex<double> P;
typedef pair<P, P> L;
typedef pair<P, double> C;

int dx[]={1, -1, 0, 0};
int dy[]={0, 0, 1, -1};
int const MOD = 1000000007;
ll mod_pow(ll x, ll n) {return (!n)?1:(mod_pow((x*x)%MOD,n/2)*((n&1)?x:1))%MOD;}
int madd(int a, int b) {return (a + b) % MOD;}
int msub(int a, int b) {return (a - b + MOD) % MOD;}
int mmul(int a, int b) {return (a * b) % MOD;}
int minv(int a) {return mod_pow(a, MOD-2);}
int mdiv(int a, int b) {return mmul(a, minv(b));}

namespace std {
    bool operator<(const P& a, const P& b) {
        return a.X != b.X ? a.X < b.X : a.Y < b.Y;
    }
}

int h, w;
char board[110][110];
string hasu = "STo";

template <typename T>
struct Edge {
    int to; T cap, cost; int rev;
    Edge(int t, T c, int r) : to(t), cap(c), rev(r) {}
    Edge(int t, T ca, T co, int r) : to(t), cap(ca), cost(co), rev(r) {}
};

template <typename T>
using Graph = vector< vector< Edge<T> > >;

template<typename T>
struct Dinic {
    int N, M;
    Graph<T> G;
    vector<int> level, iter;
    Dinic(int n, int m) : N(n), M(m) {
        G.resize(N);
        level.resize(N);
        iter.resize(N);
    }
    void add_edge(int from, int to, T cost) {
        G[from].push_back(Edge<T>(to  , cost, G[to  ].size()    ));
        G[to  ].push_back(Edge<T>(from, 0.0 , G[from].size() - 1));
    }
    void readGraph() {
        for(int i=0; i<M; i++) {
            int a, b; T c;
            cin >> a >> b >> c;
            // a--; b--;
            add_edge(a, b, c);
        }
    }
    void bfs(int s) {
        fill(level.begin(), level.end(), -1);
        queue<int> que; que.push(s);
        level[s] = 0;
        while(!que.empty()) {
            int temp = que.front(); que.pop();
            for(size_t i=0; i<G[temp].size(); i++) {
                Edge<T> &e = G[temp][i];
                if(e.cap > 0 && level[e.to] < 0) {
                    level[e.to] = level[temp] + 1;
                    que.push(e.to);
                }
            }
        }
    }
    T dfs(int v, int t, T f) {
        if(v == t) return f;
        for(int &i = iter[v]; i<(int)G[v].size(); i++) {
            Edge<T> &e = G[v][i];
            if(e.cap > 0 && level[v] < level[e.to]) {
                T d = dfs(e.to, t, min(f, e.cap));
                if(d > 0) {
                    e.cap -= d;
                    G[e.to][e.rev].cap += d;
                    return d;
                }
            }
        }
        return 0;
    }
    T max_flow(int s, int t) {
        T flow = 0.0, f;
        while(1) {
            bfs(s);
            if(level[t] < 0) return flow;
            fill(iter.begin(), iter.end(), 0);
            while( (f = dfs(s, t, INF)) > 0 ) flow += f;
        }
    }
};

int getindex(int x, int y) {
    return (x*w + y)*2;
}

signed main() {
    cin >> h >> w;
    // Flow<int> fl(2*h*w);
    Dinic<int> fl(2*h*w, 0);
    int s, t;
    rep(i,0,h) rep(j,0,w) {
        cin >> board[i][j];
        if(board[i][j] == 'S') s = getindex(i, j) + 1;
        if(board[i][j] == 'T') t = getindex(i, j);
        int idx = getindex(i, j);
        fl.add_edge(idx, idx+1, 1);
    }

    bool ng = false;
    rep(i,0,h) rep(j,0,w) {
        if(hasu.find(board[i][j]) == string::npos) continue;
        rep(x,i+1,h) {
            if(i == x) continue;
            if(hasu.find(board[x][j]) == string::npos) continue;
            if((board[i][j] == 'S' && board[x][j] == 'T') ||
               (board[i][j] == 'T' && board[x][j] == 'S')) {
                ng = true; continue;
            }
            fl.add_edge(getindex(i, j) + 1, getindex(x, j), 1);
            fl.add_edge(getindex(x, j) + 1, getindex(i, j), 1);
        }
        rep(y,j+1,w) {
            if(hasu.find(board[i][y]) == string::npos) continue;
            if((board[i][j] == 'S' && board[i][y] == 'T') ||
               (board[i][j] == 'T' && board[i][y] == 'S')) {
                ng = true; continue;
            }
            fl.add_edge(getindex(i, j) + 1, getindex(i, y), 1);
            fl.add_edge(getindex(i, y) + 1, getindex(i, j), 1);
        }
    }
    if(ng) cout << -1 << endl;
    else cout << fl.max_flow(s, t) << endl;
    return 0;
}

Measured memory_bytes: 166400