#include <bits/stdc++.h>
using namespace std;
//#define cerr if (false) cerr
#define db(x) cerr << #x << "=" << x << endl
#define db2(x, y) cerr << #x << "=" << x << "," << #y << "=" << y << endl
#define db3(x, y, z) cerr << #x << "=" << x << "," << #y << "=" << y << "," << #z << "=" << z << endl
#define dbv(v) cerr << #v << "="; for (auto _x : v) cerr << _x << ", "; cerr << endl
#define dba(a, n) cerr << #a << "="; for (int _i = 0; _i < (n); ++_i) cerr << a[_i] << ", "; cerr << endl
template <typename A, typename B>
ostream& operator<<(ostream& os, const pair<A, B>& x) {
	return os << "(" << x.first << "," << x.second << ")";
}
typedef long long ll;
typedef long double ld;
template <typename T>
struct Dinic {
	// vertices are 0..n-1
	static const T eps = 1e-9;
	int n, src, sink;
	struct Edge {
		int from, to;
		T f, cap;
	};
	vector<int> dist, Q, work;
	vector<Edge> edges;
	vector<vector<int>> G;
	Dinic(int _n) : n(_n) {
		G.resize(n);
		dist.resize(n);
		Q.resize(n);
		work.resize(n);
	}
	// Returns edge id added (rev edge is id ^ 1)
	int addEdge(int s, int t, T forwardCap, T backwardCap = 0) {
		int id = edges.size();
		G[s].push_back(id);
		edges.push_back({s, t, 0, forwardCap});
		G[t].push_back(id + 1);
		edges.push_back({t, s, 0, backwardCap});
		return id;
	}
	bool dinicBfs() {
		fill(dist.begin(), dist.begin() + n, -1);
		dist[src] = 0;
		int qt = 0;
		Q[qt++] = src;
		for (int qh = 0; qh < qt; ++qh) {
			int u = Q[qh];
			for (int eid : G[u]) {
				Edge& e = edges[eid];
				int v = e.to;
				if (dist[v] < 0 && e.cap - e.f > eps) {
					dist[v] = dist[u] + 1;
					Q[qt++] = v;
				}
			}
		}
		return dist[sink] >= 0;
	}
	T dinicDfs(int u, T f) {
		if (u == sink) return f;
		// Edges 0..work[u] - 1 have been saturated
		for (int& i = work[u]; i < G[u].size(); ++i) {
			int eid = G[u][i];
			Edge& e = edges[eid];
			if (e.cap <= e.f) continue;
			int v = e.to;
			if (dist[v] == dist[u] + 1) {
				T df = dinicDfs(v, min(f, e.cap - e.f));
				if (df > 0) {
					e.f += df;
					edges[eid ^ 1].f -= df;
					return df;
				}
			}
		}
		return 0;
	}
	T maxFlow() {
		assert(src != -1 && sink != -1);
		T result = 0;
		while (dinicBfs()) {
			fill(work.begin(), work.begin() + n, 0);
			for (;;) {
				T delta = dinicDfs(src, numeric_limits<T>::max());
				if (delta <= eps) break;
				result += delta;
			}
		}
		return result;
	}
	vector<bool> minCut() {
		maxFlow();
		vector<bool> ret(n);
		for (int i = 0; i < n; ++i)
			ret[i] = dist[i] >= 0;
		return ret;
	}
	// Matching, A={0..na-1}, B={0..nb-1}.
	int na, nb;
	vector<int> matcha, matchb;
	Dinic(int _na, int _nb) : Dinic(_na + _nb + 2) {
		na = _na;
		nb = _nb;
		src = n - 2;
		sink = n - 1;
		for (int i = 0; i < na; ++i) addEdge(src, i, 1);
		for (int i = 0; i < nb; ++i) addEdge(na + i, sink, 1);
	}
	int addMatchEdge(int s, int t) {
		return addEdge(s, t + na, 1);
	}
	int maxMatching() {
		int ret = maxFlow();
		matcha.resize(na);
		matchb.resize(nb);
		for (int i = 0; i < na; ++i) {
			for (int eid : G[i]) {
				auto& e = edges[eid];
				if (e.to != src && e.f == 1) {
					matcha[i] = e.to - na;
					matchb[e.to - na] = i;
				}
			}
		}
		return ret;
	}
};
char G[105][105];
int main() {
	int H, W;
	scanf("%d%d", &H, &W);
	Dinic<int> g(H + W + 2);
	g.src = H + W;
	g.sink = g.src + 1;
	const int INF = 1e8;
	for (int i = 0; i < H; ++i) {
		scanf("%s", G[i]);
		for (int j = 0; j < W; ++j) {
			if (G[i][j] == 'o') {
				g.addEdge(i, H + j, 1, 1);
			} else if (G[i][j] == 'S') {
				g.addEdge(g.src, i, INF);
				g.addEdge(g.src, H + j, INF);
			} else if (G[i][j] == 'T') {
				g.addEdge(i, g.sink, INF);
				g.addEdge(H + j, g.sink, INF);
			}
		}
	}
	int ans = g.maxFlow();
	printf("%d\n", ans >= INF ? -1 : ans);
}


Measured memory_bytes: 948