#define _GLIBCXX_DEBUG
#include <bits/stdc++.h>
using namespace std;

template<class T>
struct Dinic {
private : 
    const T INF = numeric_limits<T>::max();
    struct Edge {
        int to, rev; T cap;
        Edge (int to, T cap, int rev)
            : to(to), cap(cap), rev(rev) { }
    };
    vector<int> level, idx;
    vector<vector<Edge>> g;
public : 
    Dinic (int n) : g(n), level(n), idx(n) { }

    void add_edge (int from, int to, T cost) {
        g[from].emplace_back(to, cost, g[to].size());
        g[to].emplace_back(from, 0, g[from].size() - 1);
    }

    void init (int s) {
        fill(level.begin(), level.end(), -1); level[s] = 0;
        queue<int> que; que.emplace(s);
        while (not que.empty()) {
            const int v = que.front(); que.pop();
            for (const Edge &e : g[v]) {
                if (e.cap > 0 and level[e.to] < 0) {
                    level[e.to] = level[v] + 1;
                    que.emplace(e.to);
                }
            }
        }
    }

    T find_flow (int v, int t, T f) {
        if (v == t) return f;
        for (int &i = idx[v]; i < g[v].size(); i++) {
            Edge &e = g[v][i];
            if (e.cap > 0 and level[v] < level[e.to]) {
                const T flow = find_flow(e.to, t, min(f, e.cap));
                if (flow > 0) {
                    e.cap -= flow;
                    g[e.to][e.rev].cap += flow;
                    return flow;
                }
            }
        }
        return 0;
    }

    T max_flow (int s, int t) {
        T ret = 0;
        while (true) {
            init(s);
            if (level[t] < 0) break;
            fill(idx.begin(), idx.end(), 0);
            while (true) {
                T flow = find_flow(s, t, INF);
                if (flow <= 0) break;
                ret += flow;
            }
        }
        return ret;
    }

};

bool check (const vector<string> &s) {
    const int h = s.size(), w = s[0].size();
    bool ret = false;
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (s[i][j] == 'S') {
                for (int k = 0; k < h; k++) ret |= (s[k][j] == 'T');
                for (int k = 0; k < w; k++) ret |= (s[i][k] == 'T');
            }
        }
    }
    return ret;
}

int main() {
    constexpr int INF = 100000;
    int h, w;
    cin >> h >> w;
    vector<string> s(h);
    for (string &e : s) cin >> e;
    if (check(s)) { cout << -1 << '\n'; return 0; }

    int start = -1, goal = -1;
    Dinic<int> g(h * w * 2);
    
    auto index = [&] (int i, int j) { return (i * w + j); };
    auto outdex = [&] (int i, int j) { return (index(i, j) + h * w); };
    
    for (int i = 0; i < h; i++) for (int j = 0; j < w; j++) {
        if (s[i][j] == '.') continue;
        if (s[i][j] == 'T') { goal = index(i, j); continue; }
        if (s[i][j] == 'S') start = index(i, j);
        if (s[i][j] == 'o') { g.add_edge(index(i, j), outdex(i, j), 1); };
        for (int k = 0; k < h; k++) if (i != k and s[k][j] != '.' and s[k][j] != 'S') {
            if (s[i][j] == 'S') g.add_edge(start, index(k, j), INF);
            else g.add_edge(outdex(i, j), index(k, j), INF);
        }
        for (int k = 0; k < w; k++) if (j != k and s[i][k] != '.' and s[i][k] != 'S') {
            if (s[i][j] == 'S') g.add_edge(start, index(i, k), INF);
            else g.add_edge(outdex(i, j), index(i, k), INF);
        }
    }
    
    int ans = g.max_flow(start, goal);
    
    cout << ans << '\n';
    
    return 0;
}

Measured memory_bytes: 63232