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

// usage:
// MaxFlowDinic::init(n);
// MaxFlowDinic::add_edge(0, 1, 100, 100); // for bidirectional edge
// MaxFlowDinic::add_edge(1, 2, 100); // directional edge
// result = MaxFlowDinic::solve(0, 2); // source -> sink
// graph[i][edgeIndex].res -> residual
//
// in order to find out the minimum cut, use `l'.
// if l[i] == 0, i is unrechable.
//
// O(V*V*E)
// with unit capacities, O(min(V^(2/3), E^(1/2)) * E
struct MaxFlowDinic {
    typedef int flow_t;
    struct Edge {
        int next;
        size_t inv; /* inverse edge index */
        flow_t res; /* residual */
    };
    int n;
    vector<vector<Edge>> graph;
    vector<int> q, l, start;
    void init(int _n) {
        n = _n;
        graph.resize(n);
        for (int i = 0; i < n; i++) graph[i].clear();
    }
    void add_edge(int s, int e, flow_t cap, flow_t caprev = 0) {
        Edge forward{ e, graph[e].size(), cap };
        Edge reverse{ s, graph[s].size(), caprev };
        graph[s].push_back(forward);
        graph[e].push_back(reverse);
    }
    bool assign_level(int source, int sink) {
        int t = 0;
        memset(&l[0], 0, sizeof(l[0]) * l.size());
        l[source] = 1;
        q[t++] = source;
        for (int h = 0; h < t && !l[sink]; h++) {
            int cur = q[h];
            for (const auto& e : graph[cur]) {
                if (l[e.next] || e.res == 0) continue;
                l[e.next] = l[cur] + 1;
                q[t++] = e.next;
            }
        }
        return l[sink] != 0;
    }
    flow_t block_flow(int cur, int sink, flow_t current) {
        if (cur == sink) return current;
        for (int& i = start[cur]; i < graph[cur].size(); i++) {
            auto& e = graph[cur][i];
            if (e.res == 0 || l[e.next] != l[cur] + 1) continue;
            if (flow_t res = block_flow(e.next, sink, min(e.res, current))) {
                e.res -= res;
                graph[e.next][e.inv].res += res;
                return res;
            }
        }
        return 0;
    }
    flow_t solve(int source, int sink) {
        q.resize(n);
        l.resize(n);
        start.resize(n);
        flow_t ans = 0;
        while (ans < (int)1e9 && assign_level(source, sink)) {
            memset(&start[0], 0, sizeof(start[0]) * n);
            while (flow_t flow = block_flow(source, sink, numeric_limits <flow_t
                        >::max()))
                ans += flow;
        }
        return ans;
    }
};

char dat[105][105];
int n, m;

int index(int x, int y)
{
    return (x * m + y) * 2;
}

int main()
{
    scanf("%d%d",&n,&m);

    for (int i = 0; i < n; i++) scanf("%s", dat[i]);

    MaxFlowDinic mf;
    mf.init(n * m * 2);

    int sx, sy, ex, ey;

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            if (dat[i][j] == '.') continue;
            if (dat[i][j] == 'o') mf.add_edge(index(i, j) + 1, index(i, j), 1);
            if (dat[i][j] == 'S') sx = i, sy = j;
            if (dat[i][j] == 'T') ex = i, ey = j;

            for (int k = 0; k < n; k++)
            {
                if (i == k || dat[k][j] == '.') continue;
                mf.add_edge(index(k, j), index(i, j) + 1, 1e9);
            }

            for (int k = 0; k < m; k++)
            {
                if (j == k || dat[i][k] == '.') continue;
                mf.add_edge(index(i, k), index(i, j) + 1, 1e9);
            }
        }
    }

    int res = mf.solve(index(sx, sy), index(ex, ey) + 1);
    if (res >= (int)1e9) printf("-1\n");
    else printf("%d\n", res);
}


Measured memory_bytes: 124544