#include<bits/stdc++.h>
using namespace std;
template<typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')';}
template<typename T_container, typename T = typename enable_if<!is_same<T_container, string>::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) {os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; }
void dbg_out() { cerr << endl; }
template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); }
template<typename T> void dbg_a(T *a,int l,int r){cerr<<" {";for(int i = l;i<r;i++) cerr<<a[i]<<", ";cerr<<a[r]<<"}"<<endl;}
typedef long long ll;
#define int ll
//typedef unsigned long long ull;
inline int read(){
    int f(1),r(0);char c(getchar());
    while(c<'0'||c>'9'){if(c == '-') f = -1; c = getchar();}
    while(c>='0'&&c<='9'){ r = (r<<1) + (r<<3) + c - '0';c = getchar();}
    return f*r;
}
typedef pair<int,int> PII;
#define fi first
#define se second
#define mst(a,b) memset(a,b,sizeof(a))
#define For(i,a,b) for(int i = a;i<=b;i++)
#define For_(i,a,b) for(int i = a;i>=b;i--)
#define _for(i,a) for(int i = 0;i<a;i++)
#define _sum(a,l,r) accumulate(a + l,a + r + 1,0)
#define All(x) x.begin(),x.end()
#define lowbit(x) ((-x)&x)
//    For(i,1,n) For(j,1,m) printf("f[%lld][%lld] = %lld\n",i,j,f[i][j]);
//const ll INF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int N = 100 + 6,M = 2e5*2 + 6,Q = 2e6 + 5;
const int mod = 1e9 + 7;
int n,m,k;
struct UFs{
    vector<int> pre,num;
    UFs(int l){
        pre.resize(l+1);num.resize(l+1);
        for(int i = 0;i<=l;i++) pre[i] = i,num[i] = 1;
    }
    int Find(int x){
        int p = x,tmp;
        while(x != pre[x]) x = pre[x];
        while(x != p){ tmp = pre[p];pre[p] = x;p = tmp;}
        return x;
    }
    void join(int x,int y){//插到y上
        int q = Find(x),p = Find(y);
        if(q == p) return ;
        pre[q] = p; num[p] += num[q];
    }
    bool same(int x,int y){
        return Find(x) == Find(y);
    }
    bool is_root(int x){
        return pre[x] == x;
    }
};
int clr[N];
bool vis[N];
vector<int> G[25];
vector<int> v;
void dfs2(int x){
    v.emplace_back(x);
    vis[x] = 1;
    for(int y:G[x]){
        if(vis[y]) continue;
        dfs2(y);
    }
}
int res = 0;
void dfs(int idx){
    if(idx == v.size()){
        res++;
        return ;
    }
    set<int> s;
    s.insert({1,2,3});
    for(int y:G[v[idx]]){
        s.erase(clr[y]);
    }
    for(int c:s){
        clr[v[idx]] = c;
        dfs(idx + 1);
        clr[v[idx]] = 0;
    }
}

void solve(){
    n = read(),m = read();
    UFs ufs(n);
    For(i,1,m){
        int x = read(),y = read();
        G[x].emplace_back(y);
        G[y].emplace_back(x);
        ufs.join(x,y);   
    }
    int ans = 1;

    For(i,1,n){
        if(ufs.is_root(i)){
            v.clear();
            dfs2(i);
            res = 0;
            dfs(0);
            ans *= res;
        }
    }
    cout<<ans<<"\n";    
}


signed main(){
    int T = 1;
    //T = read();
    while(T--) solve();
    return 0;
}
#include <iostream>
#include <vector>
#include <queue>
#include <string>
using namespace std;
struct edge{
    int to;
    int cost;
};
int main(){
    int H, W;
    cin >> H >> W;
    vector<string> S(H);
    for(int i = 0; i < H; i++) cin >> S[i];
    int gi = 0, gj = 0, si = 0, sj = 0;
    int INF = 1e9;
    vector<int> d(H * W + 26, INF);
    vector<vector<edge>> alp(H * W + 26);
    for(int i = 0; i < H; i++){
        for(int j = 0; j < W; j++){
            if(S[i][j] == 'G'){
                gi = i;
                gj = j;
            }
            else if(S[i][j] == 'S'){
                si = i;
                sj = j;
            }
            else if('a' <= S[i][j] && S[i][j] <= 'z'){
                int ind = S[i][j] - 'a';
                alp[H * W + ind].push_back({i * W + j, 1});
                alp[i * W + j].push_back({H * W + ind, 0});
            }
        }
    }
    deque<int> q;
    q.push_back(si * W + sj);
    d[si * W + sj] = 0;
    int dx[4] = {0, -1, 0, 1}, dy[4] = {-1, 0, 1, 0};
    while(!q.empty()){
        int t = q.front();
        q.pop_front();
        if(t >= H * W){
            for(edge v: alp[t]){
                if(d[v.to] == INF){
                    d[v.to] = d[t] + v.cost;
                    if(v.cost == 0) q.push_front(v.to);
                    else q.push_back(v.to);
                }
            }
        }
        else{
            int x = t / W, y = t % W;  
            for(int i = 0; i < 4; i++){
                int nx = dx[i] + x, ny = dy[i] + y;
                if(0 <= nx && nx < H && 0 <= ny && ny < W && d[nx * W + ny] == INF && S[nx][ny] != '#'){
                    d[nx * W + ny] = d[t] + 1;
                    q.push_back(nx * W + ny);
                }
            }
            for(edge v: alp[t]){
                if(d[v.to] == INF){
                    d[v.to] = d[t] + v.cost;
                    if(v.cost == 0) q.push_front(v.to);
                    else q.push_back(v.to);
                }
            }
        }
    }
    if(d[gi * W + gj] == INF) cout << -1 << endl;
    else cout << d[gi * W + gj] << endl;
}