#include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <utility>
#include <functional>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <climits>
#include <cassert>
using namespace std;
inline int toInt(string s) {int v; istringstream sin(s);sin>>v;return v;}
template<class T> inline string toString(T x) {ostringstream sout;sout<<x;return sout.str();}
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<string> vs;
typedef pair<int, int> pii;
typedef long long ll;
#define ALL(a) (a).begin(),(a).end()
#define RALL(a) (a).rbegin(),(a).rend()
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
const double EPS = 1e-10;
const double PI  = acos(-1.0);


	int w,h;
	const int MAX=INT_MAX/10;
struct node{
    int y,x,cost;
    node(int y,int x,int cost):y(y),x(x),cost(cost){}
    bool operator<(const node& other)const{
        return cost>other.cost;
    }
};
const int NONE=-1;
int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
int search(vs &field,vvi &time,pii start,pii goal){
    priority_queue<node> q;
	q.push(node(start.first,start.second,0));
    vvi cost(h,vi(w,MAX));
    cost[start.first][start.second]=0;
    while(!q.empty()){
        node cnode=q.top();q.pop();
		if(cost[cnode.y][cnode.x]<cnode.cost){
            continue;
        }
		REP(d,4){
			int xx=cnode.x+dx[d];
			int yy=cnode.y+dy[d];
			if(xx>=0&&yy>=0&&xx<w&&yy<h&&field[yy][xx]!='#'){
				int newcost=cnode.cost+time[cnode.y][cnode.x];
				if(cost[yy][xx]>newcost){
					cost[yy][xx]=newcost;
					q.push(node(yy,xx,newcost));
				}
            }
        }
    }
	return cost[goal.first][goal.second];
}
int main(){
	cin>>w>>h;
	vs field(h);
	vector<pii> points;
	REP(i,h){
		cin>>field[i];
	}
	REP(i,h){
		REP(j,w){
			if(field[i][j]=='M'){
				points.push_back(make_pair(i,j));
			}
		}
	}
	REP(i,h){
		REP(j,w){
			if(field[i][j]=='S'){
				points.push_back(make_pair(i,j));
			}
		}
	}
	REP(i,h){
		REP(j,w){
			if(field[i][j]=='G'){
				points.push_back(make_pair(i,j));
			}
		}
	}

	vvi time(h,vi(w,1));
	REP(i,h){
		REP(j,w){
			int nearest=MAX;
			FOR(x,-3,3+1){
				FOR(y,-3,3+1){
					if(x==0&&y==0)continue;
					int yy=i+y,xx=j+x;
					if(yy>=0&&xx>=0&&yy<h&&xx<w&&field[i+y][j+x]=='#'){
						nearest=min(nearest,max(abs(x),abs(y)));
					}
				}
			}
			if(nearest!=MAX){
				time[i][j]=4-nearest;
			}
		}
	}
	vvi dist(points.size(),vi(points.size()));
	REP(i,points.size()){
		REP(j,points.size()){
			if(i!=j){
				dist[i][j]=search(field,time,points[i],points[j]);
			}
		}
	}
	vi order(points.size()-2);
	REP(i,order.size()){
		order[i]=i;
	}
	int ans=MAX;
	do{
		int cost=0;
		cost+=dist[order.size()][order[0]];
		REP(i,order.size()-1){
			cost+=dist[order[i]][order[i+1]];
		}
		cost+=dist[order[order.size()-1]][order.size()+1];
		ans=min(ans,cost);
	}while(next_permutation(ALL(order)));
	cout<<ans<<endl;
}