#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
typedef long long   ll;
#define pb                push_back
#define mp                make_pair
#define all(a)            (a).begin(), (a).end()
#define clr(a,h)          memset(a, (h), sizeof(a))
#define mem(a,h)          memset(a, (h), sizeof(a))
#define fi first
#define se second
#define por(a,b) (((a%MOD) * (b%MOD))%MOD)
#define forg(i, b, e, c)    for (ll i = (ll)b; i < (ll)e; i+=c)
#define forr(i, b, e)    for (ll i = b; i < e; i++)
 
 
using namespace std;
//using namespace __gnu_pbds;
typedef double lldb;
typedef pair<ll, ll>  ii;
typedef pair<ii, ll>  iii;
typedef vector<ll>     vi;
typedef vector<vi>     vvi;
typedef vector<ii>      vii;
typedef vector<ll>      vll;
//typedef tree<ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> ordered_set;
const ll INF = 1e9;
const double PI = acos(-1);
#define offset 
const ll MOD= 1e9+7;
#define initseg ll new_nodo=(nodo*2),mid=(iz+der)/2;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int tam = 30000;

int S, T;
int n;
int dist[tam], q[tam], work[tam];

struct Edge {
    int to, rev;
    int f, cap;
};

vector<Edge> G[tam];

void addEdge(int s, int t, int cap)
{
    Edge a = {t, (int)G[t].size(), 0, cap};
    Edge b = {s, (int)G[s].size(), 0, 0};
    G[s].pb(a);
    G[t].pb(b);
}

bool dinic_BFS(){
    fill(dist, dist + n + 2, -1);
    dist[S] = 0;
    int qt = 0;
    q[qt++] = S;
    for (int qh = 0; qh < qt; qh++)
    {
        int u = q[qh];
        for (int j = 0; j < G[u].size(); j++)
        {
            Edge &e = G[u][j];
            int v = e.to;
            if (dist[v] < 0 && e.f < e.cap)
            {
                dist[v] = dist[u] + 1;
                q[qt++] = v;
            }
        }
    }
    return dist[T] >= 0;
}

int dinic_DFS(int u, int f)
{
    if (u == T || f == 0) return f;
    for (int &i = work[u]; i < G[u].size(); i++)
    {
        Edge &e = G[u][i];
        if (e.cap <= e.f) continue;
        int v = e.to;
        if (dist[v] == dist[u] + 1)
        {
            int df = dinic_DFS(v, min(f, e.cap - e.f));
            if (df > 0)
            {
                e.f += df;
                G[v][e.rev].f -= df;
                return df;
            }
        }
    }
    return 0;
}

int maxFlow()
{
    int flow = 0;
    while ( dinic_BFS() )
    {
        fill(work, work + n + 2, 0);
        while (true)
        {
            int df = dinic_DFS(S, INF);
            if (df == 0) break;
            flow += df;
        }
    }
    return flow;
}
int N,M;
string txt[tam];
int getnod(int y,int x)
{
    return y*M+x;
}
void go(int i,int j)
{
    int inicial=getnod(i,j),final;
    addEdge(inicial*2,inicial*2+1,1);
    forr(k,0,M)
    {
        if (txt[i][k]!='.')
        {
            final=getnod(i,k);
            addEdge(inicial*2+1,final*2,INF);
        }
    }
    forr(k,0,N)
    {
        if (txt[k][j]!=',')
        {
            final=getnod(k,j);
            addEdge(inicial*2+1,final*2,INF);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    
    cin>>N>>M;
    n=getnod(N,M)*2+1;
    int inicial,final;
    int y,x;
    forr(i,0,N)
    {
        cin>>txt[i];
        forr(j,0,M)
        {
            if (txt[i][j]=='S'){
                S=getnod(i,j)*2;
                y=i;x=j;
                continue;
            }
            if (txt[i][j]=='T'){
                T=getnod(i,j)*2;
                continue;
            }
            if (txt[i][j]=='.')continue;
            go(i,j);
            
        }
    }

    forr(k,0,M)
    {
        if (txt[y][k]!='.')
        {
            final=getnod(y,k);

            addEdge(S,final*2,INF);
        }
    }
    forr(k,0,N)
    {
        if (txt[k][x]!=',')
        {
            final=getnod(k,x);
            addEdge(S,final*2,INF);
        }
    }
    int res=maxFlow();
    if (res<INF)
        cout<<res<<endl;
    else
        cout<<-1<<endl;

}
// PLUS ULTRA!ac

Measured memory_bytes: 83968