#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef complex<double> P;
typedef pair<int,int> pii;
#define REP(i,n) for(ll i=0;i<n;++i)
#define REPR(i,n) for(ll i=1;i<n;++i)
#define FOR(i,a,b) for(ll i=a;i<b;++i)

#define DEBUG(x) cout<<#x<<": "<<x<<endl
#define DEBUG_VEC(v) cout<<#v<<":";REP(i,v.size())cout<<" "<<v[i];cout<<endl
#define ALL(a) (a).begin(),(a).end()

#define MOD (ll)(1e9+7)
#define ADD(a,b) a=((a)+(b))%MOD
#define FIX(a) ((a)%MOD+MOD)%MOD

#define INF 1e9

// splatoooooooooooooooooon

int masu[100][100];
int w,h;
int pos(int y, int x){
  return y*w+x;
}
int MAX_POS(){
  return pos(h-1,w-1)+1;
}
int getx(int p){
  return p%w;
}
int gety(int p){
  return p/w;
}

// struct vertex{int dst,pre;};
struct edge{int from,to,w;};
bool operator < (const edge &e, const edge &f) {
  return e.w != f.w ? e.w > f.w :
    e.from != f.from ? e.from < f.from : e.to < f.to;
}
vi bf(vector<edge> es, int from){
  vi dst(MAX_POS());
  REP(i,MAX_POS()){
    if(i==from){
      dst[i] = 0;
    }else{
      dst[i] = INF;
    }
  }
  REP(_,MAX_POS()){
    REP(i,es.size()){
      edge e = es[i];
      dst[e.to] = min(dst[e.to], dst[e.from]+e.w);
    }
  }
  return dst;
}


// http://www.prefield.com/algorithm/graph/dijkstra.html
vi dijkstra(vector< vector<edge> > g, int s) {
  vi dist(MAX_POS());
  int n = g.size();
  dist.assign(n, INF); dist[s] = 0;
  priority_queue<edge> Q; // "e < f" <=> "e.weight > f.weight"
  for (Q.push((edge){-2, s, 0}); !Q.empty(); ) {
    edge e = Q.top(); Q.pop();
    // if (prev[e.to] != -1) continue;
    REP(i,g[e.to].size()){
      edge f = g[e.to][i];
      if (dist[f.to] > e.w+f.w) {
        dist[f.to] = e.w+f.w;
        Q.push((edge){f.from, f.to, e.w+f.w});
      }
    }
  }
  return dist;
}

int main(){
  cin >> w >> h;
  vector<string> mp(h);
  REP(i,h) cin >> mp[i];
  REP(i,h)REP(j,w)masu[i][j]=1;
  int start,goal;
  vi ms;
  REP(i,h)REP(j,w){
    if(mp[i][j] == '#'){
      // hole!
      FOR(y,-3,4)FOR(x,-3,4){
        int ny = i+y;
        int nx = j+x;
        if(ny<0 || nx<0 || ny>=h || nx>=w)continue;
        masu[ny][nx] = max(masu[ny][nx],(int)(4-max(abs(y),abs(x))));
      }
      masu[i][j] = INF;
    }
    if(mp[i][j] == 'S')start = pos(i,j);
    if(mp[i][j] == 'G')goal  = pos(i,j);
    if(mp[i][j] == 'M')ms.push_back(pos(i,j));
  }

  vector< vector<edge> > es(MAX_POS());
  REP(i,h)REP(j,w){
    if(i!=0){
      es[pos(i,j)].push_back( (edge){pos(i,j),pos(i-1,j),masu[i][j]} );
    }
    if(i!=h-1){
      es[pos(i,j)].push_back( (edge){pos(i,j),pos(i+1,j),masu[i][j]} );
    }
    if(j!=0){
      es[pos(i,j)].push_back( (edge){pos(i,j),pos(i,j-1),masu[i][j]} );
    }
    if(j!=w-1){
      es[pos(i,j)].push_back( (edge){pos(i,j),pos(i,j+1),masu[i][j]} );
    }
  }
  int cnt = 1+1+ms.size();
  int kyori[cnt][cnt];
  REP(i,cnt)REP(j,cnt)kyori[i][j]=INF;
  REP(i,cnt){
    vi ret;
    if(i==0)ret = dijkstra(es,start);
    else if(i==cnt-1)ret = dijkstra(es,goal);
    else ret = dijkstra(es,ms[i-1]);
    REP(j,cnt){
      if(j==i)continue;
      if(j==0)kyori[i][j] = ret[start];
      else if(j==cnt-1)kyori[i][j] = ret[goal];
      else kyori[i][j] = ret[ms[j-1]];
    }
  }
  REP(k,cnt)REP(i,cnt)REP(j,cnt)kyori[i][j] = min(kyori[i][j],kyori[i][k]+kyori[k][j]);

  vi perm(cnt-2);
  REP(i,cnt-2)perm[i] = i+1;
  int result = INF;
  do{
    int tmp = 0;
    tmp += kyori[0][perm[0]];
    REPR(i,cnt-2){
      tmp += kyori[perm[i-1]][perm[i]];
    }
    tmp += kyori[perm[cnt-3]][cnt-1];
    result = min(result,tmp);
  }while(next_permutation(ALL(perm)));
  cout << result << endl;
  return 0;
}

Measured memory_bytes: 3028