Problem:
Problem I:
盗まれた宝石
パル王国の国宝である宝石が盗賊たちに盗まれた。 冒険者のあなたはその噂を聞きつけて盗賊のアジトに向かい、なんとか宝石を取り戻すことが出来た。
ところが、宝石をパル王国の城へ返しに出向いたところ、城の守衛兵から、 「我が王はまだあなたを完全に信用していない。その宝石が本物かどうか怪しいし、そもそも宝石を取り戻したというのがウソで、王の命を狙う盗賊の仲間なのではないか？と疑っておられる。」 といわれた。
あなたは、守衛兵から本当に信頼できる人物かどうか試すための試練を与えられた。試練の内容は、 「城の地下倉庫へ行き指定された場所に宝石を置け。そこに宝石が本物だったときに反応する魔法陣が書かれてある。ただしあなたが怪しい行動を起こさないようにするため、地下倉庫の入り口から指定された場所に向かうまで、守衛兵が言った移動パターンをとってはならない。」 というものだった。
例えば、下図にある地下倉庫の形状、禁止パターンに対し、図にかかれてあるような移動パターンを取ってはならない。移動パターンの一部(赤くハイライトされている)が、禁止パターンの中に含まれるからである。(また、この移動パターンの中の2,3番目の動き「↓↓」も禁止パターンの中に含まれる)
一方、 下図のような移動パターンは、移動パターンのどの部分も禁止パターンの中に含まれないので許される。
入力として、地下倉庫の形状、禁止パターンが与えられる。禁止パターンを取らずに、入り口から魔法陣へ移動するのに最低限必要な移動回数を求めよ。
Input
入力には、地下倉庫の形状と禁止パターンが含まれる。
地下倉庫の形状は、以下のように表される。 まず、二つの整数 N,M が与えられる。それぞれ地下倉庫の行数と列数を意味する。(1 ≤ N,M ≤ 50)
続いて、それぞれM個の文字からなる文字列がN行与えられる。 含まれる文字とその意味は以下の通りである。
文字
意味
S
地下倉庫の入り口。一つの地下倉庫につき必ず一つだけ含まれる。
G
魔法陣。一つの地下倉庫につき必ず一つだけ含まれる。
.
通路。(禁止パターンをとらなければ)通ることが出来る。
#
壁。壁の中を通ることはできない。
次に、禁止パターンが与えられる。禁止パターンは以下のように表される。 まず、一つの整数 P が与えられる。禁止パターンの数を意味する。(0 ≤ P ≤ 10)
続いて、禁止パターンを意味する文字列がP行にわたって与えられる。 禁止パターンに含まれる文字とその意味は以下の通りである。
文字
意味
U
↑の移動。
R
→の移動。
D
↓の移動。
L
←の移動。
禁止パターンの長さは1以上、10以下である。 ある禁止パターンが、別の禁止パターンの部分文字列となっていることもある。また、同一の禁止パターンが含まれることもある。
Output
最低限必要な移動回数を意味する整数を出力せよ。魔法陣へ辿りつけない場合は -1 を出力せよ。
Notes on Test Cases
上記入力形式で複数のデータセットが与えられます。各データセットに対して上記出力形式で出力を行うプログラムを作成して下さい。
n, m が 0 のとき入力の終わりを示します。
Sample Input
7 6
......
.####.
.####.
...S#.
...##.
...##.
.....G
3
LD
DD
LLL
7 8
S#......
.#.####.
.#.#G.#.
.#.##.#.
.#....#.
.######.
........
8
DDDD
DDDU
UUUU
UUUD
RRRR
RRRL
LLLL
LLLR
3 8
########
S......G
########
2
U
D
6 10
..........
.S........
..........
..........
........G.
..........
0
6 7
.......
...#...
...#.S.
...###.
.G.....
.......
2
LL
DD
0 0
Output for Sample Input
13
60
7
10
-1

Submitted solutions:

code_snippet: #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define ULL unsigned long long
#define LL long long
using namespace std;
const int MAX_SIZE=55,MAX_P=15,max_ch=4,M=105,INF=0x3f3f3f3f;
int n,m;
struct aho_corasick{
    int next[M][max_ch],fail[M],id[300];
    bool mark[M];
    int root,L;
    int newnode(){
        for(int j=0;j<max_ch;j++) next[L][j]=-1;
        return L++;
    }
    void init(){
        L=0;
        memset(mark,0,sizeof(mark));
        root=newnode();
        id['L']=0;
        id['R']=1;
        id['U']=2;
        id['D']=3;
    }
    void insert(char buf[]){
        int len=strlen(buf);
        int now=root;
        for(int j=0;j<len;j++){
            if(next[now][id[buf[j]]]==-1) next[now][id[buf[j]]]=newnode();
            now=next[now][id[buf[j]]];
        }
        mark[now]=1;
    }
    void build(){
        queue<int>Q;
        fail[root]=root;
        for(int j=0;j<max_ch;j++){
            if(next[root][j]==-1) next[root][j]=root;
            else{
                fail[next[root][j]]=root;
                Q.push(next[root][j]);
            }
        }
        while(!Q.empty()){
            int now=Q.front();
            if(mark[fail[now]]) mark[now]=1;
            Q.pop();
            for(int j=0;j<max_ch;j++){
                if(next[now][j]==-1) next[now][j]=next[fail[now]][j];
                else{
                    fail[next[now][j]]=next[fail[now]][j];
                    Q.push(next[now][j]);
                }
            }
        }
    }
    void query(int m){
    }
}ac;
struct node{
    int x,y,z;
};
int rx[]={0,0,-1,1};
int ry[]={-1,1,0,0};
char mp[MAX_SIZE][MAX_SIZE];
int dis[MAX_SIZE][MAX_SIZE][M];
int sx,sy,tx,ty;
queue<node>Q;
bool check(int x,int y){
    return x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]!='#';
}
int bfs(){
    memset(dis,63,sizeof(dis));
    while(!Q.empty()) Q.pop();
    node now;
    now.x=sx;now.y=sy;now.z=0;
    dis[sx][sy][0]=0;
    Q.push(now);
    while(!Q.empty()){
        //printf("%d\n",1);
        now=Q.front();Q.pop();
        //printf("%d %d %d %d\n",now.x,now.y,now.z,dis[now.x][now.y][now.z]);
        for(int j=0;j<4;j++){
            int x=now.x+rx[j],y=now.y+ry[j];
            if(!check(x,y)) continue;
            int z=ac.next[now.z][j];
            if(ac.mark[z]) continue;
            if(dis[x][y][z]!=INF) continue;
            dis[x][y][z]=dis[now.x][now.y][now.z]+1;
            if(x==tx&&y==ty) return dis[x][y][z];
            Q.push({x,y,z});
        }
    }
    return -1;
}
int main() {
    //printf("%d\n",INF);
    while(scanf("%d%d",&n,&m)!=EOF&&n&&m){
        ac.init();
        for(int j=1;j<=n;j++){
            scanf("%s",mp[j]+1);
        }
        int p;
        scanf("%d",&p);
        while(p--){
            char s[15];
            scanf("%s",s);
            ac.insert(s);
        }
        //printf("1\n");
        ac.build();
        //printf("1\n");
        for(int j=1;j<=n;j++){
            for(int k=1;k<=m;k++){
                if(mp[j][k]=='S') sx=j,sy=k;
                if(mp[j][k]=='G') tx=j,ty=k;
            }
        }
        //printf("%d\n",ac.next[0][0]);
        printf("%d\n",bfs());
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4776
final_rank: 9

code_snippet: /*
7 6
......
.####.
.####.
...S#.
...##.
...##.
.....G
3
LD
DD
LLL
7 8
S#......
.#.####.
.#.#G.#.
.#.##.#.
.#....#.
.######.
........
8
DDDD
DDDU
UUUU
UUUD
RRRR
RRRL
LLLL
LLLR
3 8
########
S......G
########
2
U
D
6 10
..........
.S........
..........
..........
........G.
..........
0
6 7
.......
...#...
...#.S.
...###.
.G.....
.......
2
LL
DD
0 0

*/
#include<iostream>
#include<string>
#include<queue>
#include<vector>
#include<cassert>
#include<random>
#include<set>
#include<map>
#include<cassert>
#include<unordered_map>
#include<bitset>
#include<numeric>
#include<algorithm>
#include<optional>
#include<tuple>
#include<unordered_set>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=1<<30;
const ll INF=1LL<<62;
const ll MOD=998244353;
const ll MAXA=1e6;

using P=pair<int,int>;
struct State{
    P pos;//今いる座標の位置
    int node;//trie木でのノードのインデックス
    int dist;//スタートからの歩数
    string str;//デバッグのために使用
    State(P pos_,int node_,int dist_):pos(pos_),node(node_),dist(dist_){str="";};
};


struct Aho_Corasick{
    typedef std::unordered_map<char,int> MP;

    std::vector<MP> trie;
    std::vector<int> cnt;//cnt,treeの大きさは同じ
    const int root=0;
    
    Aho_Corasick(){
        trie.push_back(MP());
        cnt.push_back(0);
    }

    std::unordered_map<int,std::vector<std::string>> output;

    void add(const std::vector<std::string>& terms){
        for(const std::string& term:terms){
            add(term);
        }
    }

    //計算量は挿入する文字列の長さの和
    int add(const std::string& string){
        int now=root;//根
        for(char c:string){
            if(trie[now].count(c)){
                now=trie[now][c];
            }else{
                int pre=now;
                now=trie.size();
                cnt.push_back(0);
                trie.push_back(MP());
                trie[pre][c]=now;
            }
        }

        cnt[now]++;//終端文字列

        output[now].push_back(string);//終端ノードに対してsを入れる
        

        return now;
    }

    void match(const std::string& string){

        std::cout<<"target: string="<<string<<std::endl;
       
        int now=0;
        
        for(int i=0;i<string.size();i++){
            char c=string[i];
            //今の状態nowからcを用いて遷移する場所を探す.
            while(!go(now,c)){
                now=failure[now];
            }
            //go(now,string[i]).firstがtrue
            now=*go(now,c);

            for(const auto& x:output[now]){
                //ノードnowで終わる場合
                std::cout<<"start="<<i-x.size()+1<<",goal="<<i<<",string:"<<x<<std::endl;
            }
        }
        
    }


    std::vector<int> failure;
    std::vector<int> dist;
    

    //ノードnowから文字列cをうけていく場所
    std::optional<int> go(int now,char c){
        
        if(trie[now].count(c)){
            return trie[now][c];
        }else if(now==root) return root;
        else return {};
        
    }

    void bfs(){
      
      failure=std::vector<int>(trie.size(),0);
      dist=std::vector<int>(trie.size(),-1);
      std::queue<int> que;
      
      dist[root]=0;
      que.push(root);

      while(!que.empty()){
        int now=que.front();
        que.pop();
        
        for(auto [c,to]:trie[now]){
          //nowのキーc,toを取り出す
          //trie[now][c]=toとなる
         
            if(now!=root){
                int f=failure[now];//nowで失敗した場合に行きつく場所
                
                while(!go(f,c)){
                    f=failure[f];
                }
                //go(f,c).firstがtrueつまり状態fの次に文字cで行ける場所がある　もしくはfがroot
                failure[to]=*go(f,c);

                for(const auto& string:output[failure[to]]){
                    //ノードfailure[to]で終わる文字列たちをtoにもいれる
                    output[to].push_back(string);
                }
               
            }

            que.push(to);
            dist[to]=dist[now]+1;
            
        }

      }
      

    }
    
};


//U,R,D,L
const int dx[]={0,1,0,-1};
const int dy[]={-1,0,1,0};
const string dir="URDL";

vector<int> ans;

bool solve(){
    int n,m;
    cin>>n>>m;
    if(n==0 && m==0)return false;

    P start,goal;
    vector<string> s(n);
    for(int i=0;i<n;i++){
        cin>>s[i];
        for(int j=0;j<m;j++){
            if(s[i][j]=='S'){
                start={i,j};
            }
            if(s[i][j]=='G'){
                goal={i,j};
            }
        }
    }
    int p;
    cin>>p;

    Aho_Corasick trie;
    vector<string> terms(p);
    for(int i=0;i<p;i++){
        cin>>terms[i];
        trie.add(terms[i]);
    }
    trie.bfs();
    int sz=trie.trie.size();
    
    using TP=tuple<int,int,int>;
    queue<State> que;
    map<TP,int> used;//同じ状態を二度と踏まないようにするため
    que.push(State{start,trie.root,0});//初期状態
    used[make_tuple(start.first,start.second,trie.root)]=0;
    const int inf=1<<30;
    int res=inf;

    while(!que.empty()){
        State now_state=que.front();
        P pos=now_state.pos;
        int node=now_state.node;
        int d=now_state.dist;
        
        que.pop();
        if(pos==goal){
           //cout<<now_state.str<<endl;
            res=d;
            break;
               
        }

        for(int k=0;k<4;k++){
            int nx = pos.second + dx[k];
            int ny = pos.first + dy[k];

            if(nx<0 || m<=nx || ny<0 || n<=ny) continue;
            if(s[ny][nx]=='#') continue;

            //いまいるnodeからdir[k]をつけ足す場合にどこへいくか
            optional<int> res=trie.go(node,dir[k]);
          
            int next_node=0;
            if(!trie.go(node,dir[k])){
                //失敗した場合に,そこから文字dir[k]を用いて次に行くべき場所
                int f=trie.failure[node];
                while(!trie.go(f,dir[k])){
                    f=trie.failure[f];
                }
                next_node=*trie.go(f,dir[k]);


            }else{
                //次に行くべき場所.確実にわかっている
                next_node=*trie.go(node,dir[k]);
            }
            
            if(trie.output[next_node].size()==0){
                //next_nodeは終端文字でない
                State next_state{P{ny,nx},next_node,d+1};
                
                next_state.str=now_state.str+dir[k];//debugの際に使用

                if(!used.count(make_tuple(ny,nx,next_node))){
                    used[make_tuple(ny,nx,next_node)]=d+1;
                    que.push(next_state);
                   
                }
            }
            


        }
    }

    res=(res==inf?-1:res);
    ans.push_back(res);

    return true;

}


int main(){
    
    while(1){
       if(!solve()){
        break;
       }
    }
    

    for(int v:ans){
        cout<<v<<endl;
    }
}
accuracy: 1
time_ms: 260
memory_kb: 10140
final_rank: 17

code_snippet: #if 1
#include<cmath>
#include<limits>
#include<iostream>
#include<algorithm>
#include<functional>
#include<string>
#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<vector>
#include<tuple>
#include<complex>
// #include<format>
#ifdef _INTEGRAL_MAX_BITS
// #include"C:\Users\Spare\source\repos\Competitive_programming\Competitive_programming\debugging.h"
#endif
#ifndef DEBUGGING
#define MY_MAIN int main()
#define REDIRCT_IO ;
#define RESTORE_IO ;
#endif
#define sc static
#define ct const
#define ft first
#define sd second
using namespace std;
// using namespace atcoder;
// using namespace Eigen;
using ld = long double;
using ll = long long;
using cchar = const char;
using cint = const int;
using cll = const ll;
using uchar = unsigned char;
using uint = unsigned int;
using ull = unsigned long long;
using cuchar = const uchar;
using cuint = const uint;
using cull = const ull;
using clex = complex<int>;
template<class TYPE> static const TYPE INF = numeric_limits<TYPE>::max();
#define rep(i, n) for(int i = (0), fend = n; i < fend; ++i)
#define all(container) container.begin(), container.end()
static const string ascii_lowercase = "abcdefghijklmnopqrstuvwxyz";
static const string ascii_uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
cint maxN = 52, maxL = 11, maxP = 11;
int dp[maxN][maxN][maxL * maxP], N, M;
char field[maxN][maxN];
clex I(0, 1), dir(1, 0);
bool ng[maxL * maxP];
int ensuing[maxL * maxP][4];
string P[maxP];
const string RDLU = "RDLU";
cint inf = INF<int> / 2;
struct elmt { 
    clex position; int t, score; 
    elmt(clex c, int i, int i2) :position(c), t(i), score(i2){}
};

int main() {
    REDIRCT_IO;
    while (true) {
        cin >> N >> M;
        if (!N)break;
        rep(i, N + 2) { field[i][0] = field[i][M + 1] = '#'; }
        rep(i, M + 2) { field[0][i] = field[N + 1][i] = '#'; }
        clex start, goal;
        rep(i, N)rep(j, M) {
            char c;
            cin >> c;
            field[i + 1][j + 1] = c;
            if (c == 'S')start = clex(j + 1, i + 1);
            else if (c == 'G')goal = clex(j + 1, i + 1);
        }
        int p;
        cin >> p;
        rep(i, p) {
            cin >> P[i];
        }
        vector<string> pfx;
        rep(i, p) {
            for (int j = 0; j <= P[i].length(); ++j) {
                pfx.push_back(P[i].substr(0, j));
            }
        }
        sort(all(pfx));
        pfx.erase(unique(all(pfx)), pfx.end());
        int K = pfx.size();
        fill(ensuing[0], ensuing[maxL * maxP], 0);
        fill(ng, ng + maxL * maxP, false);
        rep(i, K) {
            rep(j, p) {
                ng[i] |= P[j].length() <= pfx[i].length()
                    && pfx[i].substr(pfx[i].length() - P[j].length(), P[j].length()) == P[j];
            }
            rep(j, 4) {
                string s = pfx[i] + RDLU[j];
                int k;
                while (true) {
                    k = lower_bound(all(pfx), s) - pfx.begin();
                    if (k < K && pfx[k] == s)break;
                    s = s.substr(1);
                }
                ensuing[i][j] = k;
            }
        }
        deque<elmt> deq;
        deq.push_back(elmt(start, 0, 0));
        fill(dp[0][0], dp[maxN][0], inf);
        while (!deq.empty()) {
            elmt el = deq.front(); deq.pop_front();
            clex p = el.position; int t = el.t; int s = el.score;
            if (dp[p.imag()][p.real()][t] <= s)continue;
            dp[p.imag()][p.real()][t] = s;
            rep(i, 4) {
                clex to = p + dir;
                int ensu = ensuing[t][i];
                if (field[to.imag()][to.real()] != '#' && !ng[ensu] && s + 1 < dp[to.imag()][to.real()][ensu]) {
                    deq.push_back(elmt(to, ensu, s + 1));
                }
                dir *= I;
            }
        }
        int ans = *min_element(dp[goal.imag()][goal.real()], dp[goal.imag()][goal.real()] + maxL * maxP);
        cout << (ans < inf ? ans : -1) << endl;
    }
    RESTORE_IO;
    return 0;
}
#endif
accuracy: 1
time_ms: 20
memory_kb: 4700
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef int64_t ll;

struct Node{
  int pre;
  char prec;
  map<char,int> mp;
  bool ed;
  int flgo;
  
  Node(int id,char c=' '){pre=id;prec=c;ed=false;flgo=0;}
};

struct Aho_Corasick{
  vector<Node> acnode;
  int idx;
  
  Aho_Corasick(){
     idx=0;
     acnode.push_back(Node(-1));
  }

  void add(vector<string> &kns){
    for(auto &kn : kns) add(kn);
  }
  
  int add(string &st){
    int nm=0;
    for(char c : st){
      if(acnode[nm].mp.count(c)) nm=acnode[nm].mp[c];
      else{
        idx++;
        acnode[nm].mp[c]=idx;
        acnode.push_back(Node(nm,c));
        nm=idx;
      } 
    }
    acnode[nm].ed=true;
    return nm;
  }
  
  int go(int nm,char c){
    if(acnode[nm].mp.count(c)) return acnode[nm].mp[c];
    else if(nm==0) return 0;
    else return -1;
  }
  
  void dfs(){
    int nm=0;
    queue<int> que;
    que.push(nm);
    while(!que.empty()){
      nm=que.front();
      que.pop();
      for(auto [c,to]:acnode[nm].mp){
        if(nm!=0){
          int f=acnode[nm].flgo;
          while(go(f,c)==-1){
            f=acnode[f].flgo;
          }
          acnode[to].flgo=go(f,c);
          if(acnode[acnode[to].flgo].ed) acnode[to].ed=true;
        }
        que.push(to);
      }
    }
    return;
  }

};

int main(){

  int n,m;
  vector<vector<int>> nxo={{-1,0},{1,0},{0,-1},{0,1}};
  vector<char> nxc={'U','D','L','R'};
  do{
    cin >> n >> m;
    if(n==0) break;
    
    vector g(n,vector<char>(m));
    int sn,sm,gn,gm;
    for(int i=0;i<n;i++){
      for(int j=0;j<m;j++){
        cin >> g[i][j];
        if(g[i][j]=='S'){ 
          sn=i;sm=j;
        }else if(g[i][j]=='G'){ 
          gn=i;gm=j;
        }
      }
    }
    /*for(int i=0;i<n;i++){
      for(int j=0;j<m;j++) cout << g[i][j];
      cout << endl;
    }
    break;*/
    
    int p;
    cin >> p;
    vector<string> kns;
    string st;
     for(int i=0;i<p;i++){
      cin >> st;
      kns.push_back(st);
    }
 
    Aho_Corasick ac;
    ac.add(kns);
    ac.dfs();
  /*  for(int i=0;i<=ac.idx;i++){
      cout << ac.acnode[i].pre << " " << i << " " << ac.acnode[i].prec << " " <<ac.acnode[i].flgo << " " << ac.acnode[i].ed << endl;
    }*/
    
    typedef pair<tuple<int,int,int>,int> PT;
    queue<PT> que;
    map<tuple<int,int,int>,int> used;
    PT stt={{sn,sm,0},0};
    que.push(stt);
    used[{sn,sm,0}]=1;
    int res=INT_MAX;
    int cn,cm,cnd,cnt;
    while(!que.empty()){
      stt=que.front();
      que.pop();
      tuple<int,int,int> tp;
      tie(tp,cnt)=stt;
      tie(cn,cm,cnd)=tp;
      
      if((cn==gn)&&(cm==gm)){
        res=cnt;
        break;
      }
      
      for(int i=0;i<4;i++){
        int nxn=cn+nxo[i][0],nxm=cm+nxo[i][1];
        if((nxn<0)||(nxn>=n)||(nxm<0)||(nxm>=m)) continue;
        if(g[nxn][nxm]=='#') continue;
        
        int nxnd=0;
        if(ac.go(cnd,nxc[i])==-1){
          int f=ac.acnode[cnd].flgo;
          while(ac.go(f,nxc[i])==-1){
            f=ac.acnode[f].flgo;
          }
          nxnd=ac.go(f,nxc[i]);
        }else nxnd=ac.go(cnd,nxc[i]);
        //cout << cnd << " " << nxc[i] << " " << nxnd << endl; 
        if(ac.acnode[nxnd].ed==false){
          tp={nxn,nxm,nxnd};
          if(used.count(tp)==0){
            used[tp]=1;
            que.push({tp,cnt+1});
            //cout << cnt+1 << " " << nxn << " " << nxm << " " << nxnd << endl;
          }
        }
      }
    }
    cout << (res==INT_MAX ? -1 : res) << endl;
    
   }while(true);
  return 0;
  
}
accuracy: 1
time_ms: 160
memory_kb: 9356
final_rank: 13

code_snippet: /*
AC
*/
#include<iostream>
#include<set>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<numeric>
#include<queue>
#include<cmath>
#include<cassert>
#include<unordered_map>
#include<optional>
#include<tuple>
using namespace std;
typedef long long ll;
const ll INF=1LL<<60;
typedef pair<int,int> P;
typedef pair<int,P> PP;
const ll MOD=998244353;


struct Aho_Corasick{
    typedef unordered_map<char,int> MP;

    vector<MP> trie;
    vector<int> cnt;//cnt,treeの大きさは同じ
    const int root=0;
    
    Aho_Corasick(){
        trie.push_back(MP());
        cnt.push_back(0);
    }

    unordered_map<int,vector<string>> output;

    void add(const vector<string>& terms){
        for(const string& term:terms){
            add(term);
        }
    }

    //計算量は挿入する文字列の長さの和
    int add(const string& string){
        int now=root;//根
        for(char c:string){
            if(trie[now].count(c)){
                now=trie[now][c];
            }else{
                int pre=now;
                now=trie.size();
                cnt.push_back(0);
                trie.push_back(MP());
                trie[pre][c]=now;
            }
        }

        cnt[now]++;//終端文字列

        output[now].push_back(string);//終端ノードに対してsを入れる
        

        return now;
    }

    void match(const string& string){

        cout<<"target: string="<<string<<endl;
       
        int now=0;
        
        for(int i=0;i<string.size();i++){
            char c=string[i];
            //今の状態nowからcを用いて遷移する場所を探す.
            while(!go(now,c)){
                now=failure[now];
            }
            //go(now,string[i]).firstがtrue
            now=*go(now,c);

            for(const auto& x:output[now]){
                //ノードnowで終わる場合
                cout<<"start="<<i-x.size()+1<<",goal="<<i<<",string:"<<x<<endl;
            }
        }
        
    }

    vector<int> failure;
    vector<int> dist;
    

    //ノードnowから文字列cをうけていく場所
    optional<int> go(int now,char c){
        
        if(trie[now].count(c)){
            return trie[now][c];
        }else if(now==root) return root;
        else return {};
        
    }

    void bfs(){
      
      failure=vector<int>(trie.size(),0);
      dist=vector<int>(trie.size(),-1);
      queue<int> que;
      
      dist[root]=0;
      que.push(root);

      while(!que.empty()){
        int now=que.front();
        que.pop();
        
        for(auto [c,to]:trie[now]){
          //nowのキーc,toを取り出す
          //trie[now][c]=toとなる
         
            if(now!=root){
                int f=failure[now];//nowで失敗した場合に行きつく場所
                
                while(!go(f,c)){
                    f=failure[f];
                }
                //go(f,c).firstがtrueつまり状態fの次に文字cで行ける場所がある　もしくはfがroot
                failure[to]=*go(f,c);

                for(const auto& string:output[failure[to]]){
                    //ノードfailure[to]で終わる文字列たちをtoにもいれる
                    output[to].push_back(string);
                }
               
            }

            que.push(to);
            dist[to]=dist[now]+1;
            
        }

      }
      

    }
    
};

struct State{
    
    P pos;
    int node;
    int dist;
    string str;//デバッグのために使用
    State(P pos_,int node_,int dist_):pos(pos_),node(node_),dist(dist_){str="";};
};


//U,R,D,L
const int dx[]={0,1,0,-1};
const int dy[]={-1,0,1,0};
const string dir="URDL";

vector<int> ans;

bool solve(){
    int n,m;
    cin>>n>>m;
    if(n==0 && m==0)return false;

    P start,goal;
    vector<string> s(n);
    for(int i=0;i<n;i++){
        cin>>s[i];
        for(int j=0;j<m;j++){
            if(s[i][j]=='S'){
                start={i,j};
            }
            if(s[i][j]=='G'){
                goal={i,j};
            }
        }
    }
    int p;
    cin>>p;

    Aho_Corasick trie;
    vector<string> terms(p);
    for(int i=0;i<p;i++){
        cin>>terms[i];
        trie.add(terms[i]);
    }
    trie.bfs();
    int sz=trie.trie.size();
    
    using TP=tuple<int,int,int>;
    queue<State> que;
    map<TP,int> used;//同じ状態を二度と踏まないようにするため
    que.push(State{start,trie.root,0});
    used[make_tuple(start.first,start.second,trie.root)]=0;
    const int inf=1<<30;
    int res=inf;

    while(!que.empty()){
        State now_state=que.front();
        P pos=now_state.pos;
        int node=now_state.node;
        int d=now_state.dist;
        
        que.pop();
        if(pos==goal){
           //cout<<now_state.str<<endl;
            res=d;
            break;
               
        }

        for(int k=0;k<4;k++){
            int nx = pos.second + dx[k];
            int ny = pos.first + dy[k];

            if(nx<0 || m<=nx || ny<0 || n<=ny) continue;
            if(s[ny][nx]=='#') continue;

            //いまいるnodeからdir[k]をつけ足す場合にどこへいくか
            optional<int> res=trie.go(node,dir[k]);
          
            int next_node=0;
            if(!trie.go(node,dir[k])){
                //失敗した場合に,そこから文字dir[k]を用いて次に行くべき場所
                int f=trie.failure[node];
                while(!trie.go(f,dir[k])){
                    f=trie.failure[f];
                }
                next_node=*trie.go(f,dir[k]);


            }else{
                //次に行くべき場所.確実にわかっている
                next_node=*trie.go(node,dir[k]);
            }
            
            if(trie.output[next_node].size()==0){
                //next_nodeは終端文字でない
                State next_state{P{ny,nx},next_node,d+1};
                
                next_state.str=now_state.str+dir[k];//debugの際に使用

                if(!used.count(make_tuple(ny,nx,next_node))){
                    used[make_tuple(ny,nx,next_node)]=d+1;
                    que.push(next_state);
                   
                }
            }
            


        }
    }

    res=(res==inf?-1:res);
    ans.push_back(res);

    return true;

}


int main(){
    
    while(1){
       if(!solve()){
        break;
       }
    }
    

    for(int v:ans){
        cout<<v<<endl;
    }



}
accuracy: 1
time_ms: 360
memory_kb: 9884
final_rank: 18

code_snippet: /*
AC

*/
#include<iostream>
#include<set>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<numeric>
#include<queue>
#include<cmath>
#include<cassert>
#include<unordered_map>
#include<optional>
#include<tuple>
using namespace std;
typedef long long ll;
const ll INF=1LL<<60;
typedef pair<int,int> P;
typedef pair<int,P> PP;
const ll MOD=998244353;


struct Trie{
    typedef unordered_map<char,int> MP;

    vector<MP> tree;
    vector<int> cnt;//cnt,treeの大きさは同じ
    const int root=0;
    Trie(){
        tree.push_back(MP());
        cnt.push_back(0);
    }

    unordered_map<int,vector<string>> output;

    void add(const vector<string>& terms){
        for(const string& term:terms){
            add(term);
        }
    }

    //計算量は挿入する文字列の長さの和
    int add(const string& string){
        int now=root;//根
        for(char c:string){
            if(tree[now].count(c)){
                now=tree[now][c];
            }else{
                int pre=now;
                now=tree.size();
                cnt.push_back(0);
                tree.push_back(MP());
                tree[pre][c]=now;
            }
        }

        cnt[now]++;//終端文字列

        output[now].push_back(string);//終端ノードに対してsを入れる
        

        return now;
    }

    void match(const string& string){

        cout<<"target: string="<<string<<endl;
       
        int now=0;
        
        for(int i=0;i<string.size();i++){
            char c=string[i];
            //今の状態nowからcを用いて遷移する場所を探す.
            while(!go(now,c)){
                now=failure[now];
            }
            //go(now,string[i]).firstがtrue
            now=*go(now,c);

            for(const auto& x:output[now]){
                //ノードnowで終わる場合
                cout<<"start="<<i-x.size()+1<<",goal="<<i<<",string:"<<x<<endl;
            }
        }
        
    }

    vector<int> failure;
    vector<int> dist;
    

    //ノードnowから文字列cをうけていく場所
    optional<int> go(int now,char c){
        
        if(tree[now].count(c)){
            return tree[now][c];
        }else if(now==root) return root;
        else return {};
        
    }

    void bfs(){
      
      failure=vector<int>(tree.size(),0);
      dist=vector<int>(tree.size(),-1);
      queue<int> que;
      
      dist[root]=0;
      que.push(root);

      while(!que.empty()){
        int now=que.front();
        que.pop();
        
        for(auto [c,to]:tree[now]){
          //nowのキーc,toを取り出す
          //tree[now][c]=toとなる
         
            if(now!=root){
                int f=failure[now];//nowで失敗した場合に行きつく場所
                
                while(!go(f,c)){
                    f=failure[f];
                }
                //go(f,c).firstがtrueつまり状態fの次に文字cで行ける場所がある　もしくはfがroot
                failure[to]=*go(f,c);

                for(const auto& string:output[failure[to]]){
                    //ノードfailure[to]で終わる文字列たちをtoにもいれる
                    output[to].push_back(string);
                }
               
            }

            que.push(to);
            dist[to]=dist[now]+1;
            
        }

      }
      

    }
    
};

struct State{
    
    P pos;
    int node;
    int dist;
    string str;//デバッグのために使用
    State(P pos_,int node_,int dist_):pos(pos_),node(node_),dist(dist_){str="";};
};


//U,R,D,L
const int dx[]={0,1,0,-1};
const int dy[]={-1,0,1,0};
const string dir="URDL";

vector<int> ans;

bool solve(){
    int n,m;
    cin>>n>>m;
    if(n==0 && m==0)return false;

    P start,goal;
    vector<string> s(n);
    for(int i=0;i<n;i++){
        cin>>s[i];
        for(int j=0;j<m;j++){
            if(s[i][j]=='S'){
                start={i,j};
            }
            if(s[i][j]=='G'){
                goal={i,j};
            }
        }
    }
    int p;
    cin>>p;

    Trie trie;
    vector<string> terms(p);
    for(int i=0;i<p;i++){
        cin>>terms[i];
        trie.add(terms[i]);
    }
    trie.bfs();
    int sz=trie.tree.size();
    
    using TP=tuple<int,int,int>;
    queue<State> que;
    map<TP,int> used;//同じ状態を二度と踏まないようにするため
    que.push(State{start,trie.root,0});
    used[make_tuple(start.first,start.second,trie.root)]=0;
    const int inf=1<<30;
    int res=inf;

    while(!que.empty()){
        State now_state=que.front();
        P pos=now_state.pos;
        int node=now_state.node;
        int d=now_state.dist;
        
        que.pop();
        if(pos==goal){
           //cout<<now_state.str<<endl;
            res=d;
            break;
               
        }

        for(int k=0;k<4;k++){
            int nx = pos.second + dx[k];
            int ny = pos.first + dy[k];

            if(nx<0 || m<=nx || ny<0 || n<=ny) continue;
            if(s[ny][nx]=='#') continue;

            //いまいるnodeからdir[k]をつけ足す場合にどこへいくか
            optional<int> res=trie.go(node,dir[k]);
          
            int next_node=0;
            if(!trie.go(node,dir[k])){
                //失敗した場合に,そこから文字dir[k]を用いて次に行くべき場所
                int f=trie.failure[node];
                while(!trie.go(f,dir[k])){
                    f=trie.failure[f];
                }
                next_node=*trie.go(f,dir[k]);


            }else{
                //次に行くべき場所.確実にわかっている
                next_node=*trie.go(node,dir[k]);
            }
            
            if(trie.output[next_node].size()==0){
                //next_nodeは終端文字でない
                State next_state{P{ny,nx},next_node,d+1};
                
                next_state.str=now_state.str+dir[k];//debugの際に使用

                if(!used.count(make_tuple(ny,nx,next_node))){
                    used[make_tuple(ny,nx,next_node)]=d+1;
                    que.push(next_state);
                   
                }
            }
            


        }
    }

    res=(res==inf?-1:res);
    ans.push_back(res);

    return true;

}


int main(){
    
    while(1){
       if(!solve()){
        break;
       }
    }
    

    for(int v:ans){
        cout<<v<<endl;
    }



}
accuracy: 1
time_ms: 360
memory_kb: 9884
final_rank: 18

code_snippet: /*
途中までaho-corasick

https://naoya-2.hatenadiary.org/entry/20090405/aho_corasick

*/
#include<iostream>
#include<set>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<numeric>
#include<queue>
#include<cmath>
#include<cassert>
#include<unordered_map>
#include<optional>
#include<tuple>
using namespace std;
typedef long long ll;
const ll INF=1LL<<60;
typedef pair<int,int> P;
typedef pair<int,P> PP;
const ll MOD=998244353;


struct Trie{
    typedef unordered_map<char,int> MP;

    vector<MP> tree;
    vector<int> cnt;//cnt,treeの大きさは同じ
    const int root=0;
    Trie(){
        tree.push_back(MP());
        cnt.push_back(0);
    }

    unordered_map<int,vector<string>> output;

    void add(const vector<string>& terms){
        for(const string& term:terms){
            add(term);
        }
    }

    //計算量は挿入する文字列の長さの和
    int add(const string& string){
        int now=root;//根
        for(char c:string){
            if(tree[now].count(c)){
                now=tree[now][c];
            }else{
                int pre=now;
                now=tree.size();
                cnt.push_back(0);
                tree.push_back(MP());
                tree[pre][c]=now;
            }
        }

        cnt[now]++;//終端文字列

        output[now].push_back(string);//終端ノードに対してsを入れる
        //cout<<"s="<<string<<",now="<<now<<endl;

        return now;
    }

    void match(const string& string){

        cout<<"target: string="<<string<<endl;
       
        int now=0;
        
        for(int i=0;i<string.size();i++){
            char c=string[i];
            //今の状態nowからcを用いて遷移する場所を探す.
            while(!go(now,c)){
                now=failure[now];
            }
            //go(now,string[i]).firstがtrue
            now=*go(now,c);

            for(const auto& x:output[now]){
                //ノードnowで終わる場合
                cout<<"start="<<i-x.size()+1<<",goal="<<i<<",string:"<<x<<endl;
            }
        }
        
    }

    vector<int> failure;
    vector<int> dist;
    

    //ノードnowから文字列cをうけていく場所
    optional<int> go(int now,char c){
        
        if(tree[now].count(c)){
            return tree[now][c];
        }else if(now==root) return root;
        else return {};
        
    }

    void bfs(){
      
      failure=vector<int>(tree.size(),0);
      dist=vector<int>(tree.size(),-1);
      queue<int> que;
      
      dist[root]=0;
      que.push(root);

      while(!que.empty()){
        int now=que.front();
        que.pop();
        //cout<<"now="<<now<<endl;
       
        for(auto [c,to]:tree[now]){
          //nowのキーc,toを取り出す
          //tree[now][c]=toとなる
          //cout<<"c="<<c<<",to="<<to<<endl;
          
            if(now!=root){
                //cout<<"now="<<now<<endl;
                int f=failure[now];//nowで失敗した場合に行きつく場所
                //cout<<"finit="<<f<<endl;

                while(!go(f,c)){
                //while(f!=root && !tree[f].count(c)){
                    //cout<<"f="<<f<<endl;
                    f=failure[f];
                }
                //cout<<"f="<<f<<endl;
                //cout<<"go(f,c).second="<<go(f,c).second<<endl;
                //go(f,c).firstがtrueつまり状態fの次に文字cで行ける場所がある　もしくはfがroot
                //failure[to]=(go(f,c).second);
                failure[to]=*go(f,c);

                //failure[to]=(tree[f].count(c)?tree[f][c]:root);//(go(f,c).second);
                
                for(const auto& string:output[failure[to]]){
                    //ノードfailure[to]で終わる文字列たちをtoにもいれる
                    output[to].push_back(string);
                }
               
            }

            que.push(to);
            dist[to]=dist[now]+1;
            
        }

      }
      

    }
    
};

struct State{
    
    P pos;
    int node;
    int dist;
    string str;
    State(P pos_,int node_,int dist_):pos(pos_),node(node_),dist(dist_){str="";};
};


//U,R,D,L
const int dx[]={0,1,0,-1};
const int dy[]={-1,0,1,0};
const string dir="URDL";

vector<int> ans;

bool solve(){
    int n,m;
    cin>>n>>m;
    if(n==0 && m==0)return false;

    P start,goal;
    vector<string> s(n);
    for(int i=0;i<n;i++){
        cin>>s[i];
        for(int j=0;j<m;j++){
            if(s[i][j]=='S'){
                start={i,j};
            }
            if(s[i][j]=='G'){
                goal={i,j};
            }
        }
    }
    int p;
    cin>>p;

    Trie trie;
    vector<string> terms(p);
    for(int i=0;i<p;i++){
        cin>>terms[i];
        trie.add(terms[i]);
    }
    trie.bfs();
    int sz=trie.tree.size();
    /*
    for(int i=0;i<sz;i++){
        cout<<"trie.failure["<<i<<"]="<<trie.failure[i]<<endl;
    }
    */
    
    //cout<<"te"<<endl;
    queue<State> que;
    que.push(State{start,trie.root,0});
    typedef tuple<int,int,int> TP;
    map<TP,int> used;//同じ状態を二度と踏まないようにするため
    used[make_tuple(start.first,start.second,trie.root)]=0;
    const int inf=1<<30;
    int res=inf;

    while(!que.empty()){

        //auto [pos,node,d]=que.front();
        auto now_state=que.front();
        P pos=now_state.pos;
        int node=now_state.node;
        int d=now_state.dist;
        //cout<<now_state.str<<endl;
        que.pop();
        if(pos==goal){
            //cout<<"ans string="<<now_state.str<<endl;

            res=d;
            break;
               
        }

        for(int k=0;k<4;k++){
            int nx = pos.second + dx[k];
            int ny = pos.first + dy[k];

            if(nx<0 || m<=nx || ny<0 || n<=ny) continue;
            if(s[ny][nx]=='#') continue;

            //いまいるnodeからdir[k]をつけ足す場合にどこへいくか
            optional<int> res=trie.go(node,dir[k]);
          
            int next_node=0;
            if(!trie.go(node,dir[k])){
                //失敗した場合に,そこから文字dir[k]を用いて次に行くべき場所
                int f=trie.failure[node];
                while(!trie.go(f,dir[k])){
                    f=trie.failure[f];
                }
                next_node=*trie.go(f,dir[k]);


            }else{
                //次に行くべき場所.確実にわかっている
                next_node=*trie.go(node,dir[k]);
            }
            
            //cout<<"from="<<node<<",char c="<<dir[k]<<",next_node="<<next_node<<endl;
            
            //cout<<"next_node="<<next_node<<endl;
            if(trie.output[next_node].size()==0){
                //next_nodeは終端文字でない
                State next_state{P{ny,nx},next_node,d+1};
                
                next_state.str=now_state.str+dir[k];

                if(!used.count(make_tuple(ny,nx,next_node))){
                    used[make_tuple(ny,nx,next_node)]=d+1;
                    que.push(next_state);
                   
                }
            }
            


        }
    }

    res=(res==inf?-1:res);
    //cout<<"res="<<res<<endl;
    ans.push_back(res);

    return true;

}


int main(){
    
    while(1){
       if(!solve()){
        break;
       }
    }
    

    for(int v:ans){
        cout<<v<<endl;
    }



}
accuracy: 1
time_ms: 360
memory_kb: 9908
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repd(i,a,b) for (ll i=(a);i<(b);i++)
#define rep(i,n) repd(i,0,n)
#define all(x) (x).begin(),(x).end()
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
typedef long long ll;
typedef pair<ll,ll> P;
typedef vector<ll> vec;
using Graph = vector<vector<ll>>;
const long long INF = 1LL<<60;
const long long MOD = 1000000007;
 
// Aho-Corasick
// https://youtu.be/BYoRvdgI5EU?t=9633
struct Aho {
  using MP = unordered_map<char,int>;
  vector<MP> to;
  vector<int> cnt, fail;
  Aho(): to(1), cnt(1) {}
  int add(const string& s) {
    int v = 0;
    for (char c : s) {
      if (!to[v].count(c)) {
        to[v][c] = to.size();
        to.push_back(MP());
        cnt.push_back(0);
      }
      v = to[v][c];
    }
    cnt[v]++;
    return v;
  }
  void init() {
    fail = vector<int>(to.size(), -1);
    queue<int> q;
    q.push(0);
    while (!q.empty()) {
      int v = q.front(); q.pop();
      for (auto [c,u] : to[v]) {
        fail[u] = (*this)(fail[v],c);
        cnt[u] += cnt[fail[u]];
        q.push(u);
      }
    }
  }
  int operator()(int v, char c) const {
    while (v != -1) {
      auto it = to[v].find(c);
      if (it != to[v].end()) return it->second;
      v = fail[v];
    }
    return 0;
  }
  int operator[](int v) const { return cnt[v];}
};

using F=tuple<int,int,int,int>;

int main()
{  
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    while(cin>>n>>m){
      if(n==0&&m==0)break;
      vector<string> g(n);
      rep(i,n)cin>>g[i];
      ll q;cin>>q;
      Aho aho;
      rep(qi,q){
        string s;cin>>s;
        aho.add(s);
      }
      aho.init();
      ll sz=aho.to.size();
      vector dp(n,vector(m,vector<int>(sz,1e9)));
      ll fx,fy;
      ll gx,gy;
      rep(i,n)rep(j,m){
        if(g[i][j]=='S')fx=i,fy=j;
        if(g[i][j]=='G')gx=i,gy=j;
      }
      queue<F> que;
      dp[fx][fy][0]=0;
      que.push({fx,fy,0,0});
      vec dx={-1,1,0,0},dy={0,0,1,-1};
      vector<char> memo={'U','D','R','L'};
      while(que.size()){
        auto[cx,cy,cz,cw]=que.front();
        que.pop();
        rep(i,4){
          ll nx=cx+dx[i];
          ll ny=cy+dy[i];
          ll nz=aho(cz,memo[i]);
          if(aho[nz])continue;
          if(nx<0||nx>=n||ny<0||ny>=m)continue;
          if(g[nx][ny]=='#')continue;
          if(chmin(dp[nx][ny][nz],cw+1)){
            que.push({nx,ny,nz,cw+1});
          }
        }
      }
      int ans=1e9;
      rep(i,sz){
        chmin(ans,dp[gx][gy][i]);
      }
      if(ans==1e9)ans=-1;
      cout<<ans<<'\n';
    }
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3952
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long int;
using ull = unsigned long long int;
using P = pair<ll, ll>;
using P3 = pair<ll, P>;
using PP = pair<P, P>;
constexpr int INF32 = 1 << 30;
constexpr ll INF64 = 1LL << 62;
constexpr ll MOD = 1000000007;
// constexpr ll MOD = 998244353;
constexpr int di[] = {0, 1, 0, -1};
constexpr int dj[] = {1, 0, -1, 0};
constexpr int di8[] = {0, 1, 1, 1, 0, -1, -1, -1};
constexpr int dj8[] = {1, 1, 0, -1, -1, -1, 0, 1};
constexpr double EPS = 1e-10;
const double PI = acos(-1);

#define ALL(v) (v).begin(), (v).end()
#define REP(i, n) for (int i = 0, i_len = n; i < i_len; ++i)

template<typename T1,typename T2> bool chmax(T1 &a, T2 b) { if (a<b) { a=b; return 1; } return 0; }
template<typename T1,typename T2> bool chmin(T1 &a, T2 b) { if (b<a) { a=b; return 1; } return 0; }

template <int64_t Modulus>
struct Modint {
    using mint = Modint;
    long long v;
    Modint() : v(0) {}
    Modint(long long x) {
        x %= Modulus;
        if (x < 0) x += Modulus;
        v = x;
    }
    const long long& val() const { return v; }
    // 代入演算子
    mint& operator+=(const mint rhs) {
        v += rhs.v;
        if (v >= Modulus) v -= Modulus;
        return *this;
    }
    mint& operator-=(const mint rhs) {
        if (v < rhs.v) v += Modulus;
        v -= rhs.v;
        return *this;
    }
    mint& operator*=(const mint rhs) {
        v = v * rhs.v % Modulus;
        return *this;
    }
    mint& operator/=(mint rhs) { return *this = *this * rhs.inv(); }
    // 累乗, 逆元
    mint pow(long long n) const {
        mint x = *this, res = 1;
        while (n) {
            if (n & 1) res *= x;
            x *= x;
            n >>= 1;
        }
        return res;
    }
    mint inv() const { return pow(Modulus - 2); }
    // 算術演算子
    mint operator+(const mint rhs) const { return mint(*this) += rhs; }
    mint operator-(const mint rhs) const { return mint(*this) -= rhs; }
    mint operator*(const mint rhs) const { return mint(*this) *= rhs; }
    mint operator/(const mint rhs) const { return mint(*this) /= rhs; }
    mint operator-() const { return mint() - *this; }  // 単項
    // 入出力ストリーム
    friend ostream& operator<<(ostream& os, const mint& p) { return os << p.v; }
    friend istream& operator>>(istream& is, mint& p) {
        long long t;
        is >> t;
        p = mint(t);
        return (is);
    }
};

using mint = Modint<MOD>;

struct AhoCorasick {
  private:
    static constexpr int C_SIZE = 26;    // C_SIZE  : 文字の種類数
    static constexpr int C_BEGIN = 'a';  // C_BEGIN : 開始文字
    struct Node {
        array<int, C_SIZE> to = {};  // to[c]=文字cによる遷移先ノード, 存在しなければ-1
        int id = -1;            // そのノードでマッチする文字列のID, 存在しなければ-1
        int fail = ROOT;
        int sfx = ROOT;
        Node() { to.fill(-1); }
    };

  public:
    static constexpr int ROOT = 0;
    vector<Node> nodes;
    vector<string> patterns;  // 追加した文字列
    AhoCorasick() : nodes(1) {}
    // nodes[idx]から文字cで遷移したときの頂点のindex
    int next_state(int now, char c) {
        return nodes[now].to[c - C_BEGIN];
    }
    // 文字列の追加
    void insert(const string& str) {
        patterns.push_back(str);
        int now = ROOT;
        for (char c : str) {
            int k = c - C_BEGIN;
            int& nxt = nodes[now].to[k];
            if (nxt == -1) {
                now = nxt = int(nodes.size());
                nodes.push_back(Node());
            } else {
                now = nxt;
            }
        }
        nodes[now].id = int(patterns.size())-1;
    }
    void build() {
        queue<int> que;
        for (int& x : nodes[ROOT].to) {
            if (x == -1) {
                x = ROOT;
            } else {
                que.push(x);
            }
        }
        while (!que.empty()) {
            int now = que.front();
            que.pop();
            int fail = nodes[now].fail;
            for (int k = 0; k < C_SIZE; k++) {
                int& nxt = nodes[now].to[k];
                if (nxt == -1) {                         // 遷移失敗
                    nxt = nodes[fail].to[k];        // failure link で遷移してから遷移
                } else {                                 // 遷移成功
                    nodes[nxt].fail = nodes[fail].to[k];  // 遷移先のfailure linkを求める
                    que.push(nxt);
                }
            }
            nodes[now].sfx = (nodes[fail].id != -1 ? fail : nodes[fail].sfx);
        }
    }
    // stateにマッチするすべてのパターンのidを返す
    vector<int> match(int state) {
        vector<int> res;
        int now = state;
        while (now != ROOT) {
            if (nodes[now].id != -1) res.push_back(nodes[now].id);
            now = nodes[now].sfx;
        }
        return res;
    }
    // 文字列に対応するnodeのindexを検索, 存在しなければ-1
    vector<vector<int>> search(const string& str) {
        vector<vector<int>> res;
        int now = ROOT;
        for (auto c : str) {
            int nxt = next_state(now, c);
            res.emplace_back(match(nxt));
            now = nxt;
        }
        return res;
    }
};




int solve() {
    int n, m, p;
    cin >> n >> m;
    if(n == 0) return 1;
    vector<string> s(n);
    for(int i=0;i<n;i++) cin >> s[i];
    cin >> p;
    AhoCorasick ac;
    for(int i=0;i<p;i++){
        string t;
        cin >> t;
        for(char& c : t) c = tolower(c);
        ac.insert(t);
    }
    ac.build();
    int si, sj, gi, gj;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            if(s[i][j] == 'S'){
                si = i;
                sj = j;
            }
            if(s[i][j] == 'G'){
                gi = i;
                gj = j;
            }
        }
    }
    const string dir = "rdlu";
    int l = ac.nodes.size();
    int dist[50][50][100]{};
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            fill(dist[i][j], dist[i][j]+l, INF32);
        }
    }
    queue<tuple<int,int,int>> que;
    que.push({si,sj,ac.ROOT});
    dist[si][sj][ac.ROOT] = 0;
    while(!que.empty()){
        auto [i,j,now] = que.front();
        que.pop();
        for(int k=0;k<4;k++){
            int ni = i+di[k], nj = j+dj[k];
            if(ni<0 || ni >= n || nj<0 || nj>=m) continue;
            if(s[ni][nj] == '#') continue;
            int nxt = ac.next_state(now, dir[k]);
            if(ac.match(nxt).size() > 0) continue;
            if(chmin(dist[ni][nj][nxt], dist[i][j][now]+1)){
                que.push({ni,nj,nxt});
            }
        }
    }
    int ans = INF32;
    for(int i=0;i<l;i++){
        chmin(ans, dist[gi][gj][i]);
    }
    cout << (ans < INF32 ? ans : -1) << endl;
    return 0;
}

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    // solve();
    while(!solve());
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4356
final_rank: 7

code_snippet: #define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
/*
#include <atcoder/all>
using namespace atcoder;
*/
/*
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using bll = boost::multiprecision::cpp_int;
using bdouble = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100>>;
using namespace boost::multiprecision;
*/
#if defined(LOCAL_TEST) || defined(LOCAL_DEV)
	#define BOOST_STACKTRACE_USE_ADDR2LINE
	#define BOOST_STACKTRACE_ADDR2LINE_LOCATION /usr/local/opt/binutils/bin/addr2line
	#define _GNU_SOURCE 1
	#include <boost/stacktrace.hpp>
#endif
#ifdef LOCAL_TEST
	namespace std {
		template<typename T> class dvector : public std::vector<T> {
		public:
			dvector() : std::vector<T>() {}
			explicit dvector(size_t n, const T& value = T()) : std::vector<T>(n, value) {}
			dvector(const std::vector<T>& v) : std::vector<T>(v) {}
			dvector(const std::initializer_list<T> il) : std::vector<T>(il) {}
			dvector(const std::string::iterator first, const std::string::iterator last) : std::vector<T>(first, last) {}
			dvector(const typename std::vector<T>::iterator first, const typename std::vector<T>::iterator last) : std::vector<T>(first, last) {}
			dvector(const typename std::vector<T>::reverse_iterator first, const typename std::vector<T>::reverse_iterator last) : std::vector<T>(first, last) {}
			dvector(const typename std::vector<T>::const_iterator first, const typename std::vector<T>::const_iterator last) : std::vector<T>(first, last) {}
			dvector(const typename std::vector<T>::const_reverse_iterator first, const typename std::vector<T>::const_reverse_iterator last) : std::vector<T>(first, last) {}
			T& operator[](size_t n) {
				if (this->size() <= n) { std::cerr << boost::stacktrace::stacktrace() << '\n' << "vector::_M_range_check: __n (which is " << n << ") >= this->size() (which is " << this->size() << ")" << '\n'; } return this->at(n);
			}
			const T& operator[](size_t n) const {
				if (this->size() <= n) { std::cerr << boost::stacktrace::stacktrace() << '\n' << "vector::_M_range_check: __n (which is " << n << ") >= this->size() (which is " << this->size() << ")" << '\n'; } return this->at(n);
			}
		};
		template<typename T, typename Compare = less<T>, class Allocator = allocator<T>> class dmultiset : public std::multiset<T,Compare,Allocator> {
		public:
			dmultiset() : std::multiset<T,Compare,Allocator>() {}
			dmultiset(const std::multiset<T,Compare,Allocator>& m) : std::multiset<T,Compare,Allocator>(m) {}
			dmultiset(const std::initializer_list<T> il) : std::multiset<T,Compare,Allocator>(il) {}
			dmultiset(const Compare& comp) : std::multiset<T,Compare,Allocator>(comp) {}
			const typename std::multiset<T,Compare,Allocator>::iterator erase(const typename std::multiset<T,Compare,Allocator>::iterator it) {
				return std::multiset<T,Compare,Allocator>::erase(it);
			}
			size_t erase([[maybe_unused]] const T& x) {
				std::cerr << boost::stacktrace::stacktrace() << '\n'; assert(false);
			}
			size_t erase_all_elements(const T& x) {
				return std::multiset<T,Compare,Allocator>::erase(x);
			}
		};
	}
	class dbool {
	private:
		bool boolvalue;
	public:
		dbool() : boolvalue(false) {}
		dbool(bool b) : boolvalue(b) {}
		operator bool&() { return boolvalue; }
		operator const bool&() const { return boolvalue; }
	};
	#define vector dvector
	#define multiset dmultiset
	#define bool dbool
	class SIGFPE_exception : std::exception {};
	class SIGSEGV_exception : std::exception {};
	void catch_SIGFPE([[maybe_unused]] int e) { std::cerr << boost::stacktrace::stacktrace() << '\n'; throw SIGFPE_exception(); }
	void catch_SIGSEGV([[maybe_unused]] int e) { std::cerr << boost::stacktrace::stacktrace() << '\n'; throw SIGSEGV_exception(); }
	signed convertedmain();
	signed main() { signal(SIGFPE, catch_SIGFPE); signal(SIGSEGV, catch_SIGSEGV); return convertedmain(); }
	#define main() convertedmain()
#else
	#define erase_all_elements erase
#endif
#ifdef LOCAL_DEV
	template<typename T1, typename T2> std::ostream& operator<<(std::ostream& s, const std::pair<T1, T2>& p) {
		return s << "(" << p.first << ", " << p.second << ")"; }
	template <typename T, size_t N> std::ostream& operator<<(std::ostream& s, const std::array<T, N>& a) {
		s << "{ "; for (size_t i = 0; i < N; ++i){ s << a[i] << "\t"; } s << "}"; return s; }
	template<typename T> std::ostream& operator<<(std::ostream& s, const std::set<T>& se) {
		s << "{ "; for (auto itr = se.begin(); itr != se.end(); ++itr){ s << (*itr) << "\t"; } s << "}"; return s; }
	template<typename T> std::ostream& operator<<(std::ostream& s, const std::multiset<T>& se) {
		s << "{ "; for (auto itr = se.begin(); itr != se.end(); ++itr){ s << (*itr) << "\t"; } s << "}"; return s; }
	template<typename T1, typename T2> std::ostream& operator<<(std::ostream& s, const std::map<T1, T2>& m) {
		s << "{\n"; for (auto itr = m.begin(); itr != m.end(); ++itr){ s << "\t" << (*itr).first << " : " << (*itr).second << "\n"; } s << "}"; return s; }
	template<typename T> std::ostream& operator<<(std::ostream& s, const std::deque<T>& v) {
		for (size_t i = 0; i < v.size(); ++i){ s << v[i]; if (i < v.size() - 1) s << "\t"; } return s; }
	template<typename T> std::ostream& operator<<(std::ostream& s, const std::vector<T>& v) {
		for (size_t i = 0; i < v.size(); ++i){ s << v[i]; if (i < v.size() - 1) s << "\t"; } return s; }
	template<typename T> std::ostream& operator<<(std::ostream& s, const std::vector<std::vector<T>>& vv) {
		s << "\\\n"; for (size_t i = 0; i < vv.size(); ++i){ s << vv[i] << "\n"; } return s; }
	void debug_impl() { std::cerr << '\n'; }
	template<typename Head, typename... Tail> void debug_impl(Head head, Tail... tail) { std::cerr << " " << head << (sizeof...(tail) ? "," : ""); debug_impl(tail...); }
	#define debug(...) do { std::cerr << ":" << __LINE__ << " (" << #__VA_ARGS__ << ") ="; debug_impl(__VA_ARGS__); } while (false)
	constexpr inline long long prodlocal([[maybe_unused]] long long prod, [[maybe_unused]] long long local) { return local; }
#else
	#define debug(...) do {} while (false)
	constexpr inline long long prodlocal([[maybe_unused]] long long prod, [[maybe_unused]] long long local) { return prod; }
#endif
//#define int long long
using ll = long long;
//INT_MAX = (1<<31)-1 = 2147483647, INT64_MAX = (1LL<<63)-1 = 9223372036854775807
constexpr ll INF = numeric_limits<ll>::max() == INT_MAX ? (ll)1e9 + 7 : (ll)1e18;
constexpr ll MOD = (ll)1e9 + 7; //primitive root = 5
//constexpr ll MOD = 998244353; //primitive root = 3
constexpr double EPS = 1e-9;
constexpr ll dx[4] = {1, 0, -1, 0};
constexpr ll dy[4] = {0, 1, 0, -1};
constexpr ll dx8[8] = {1, 0, -1, 0, 1, 1, -1, -1};
constexpr ll dy8[8] = {0, 1, 0, -1, 1, -1, 1, -1};
#define rep(i, n)   for(ll i=0, i##_length=(n); i< i##_length; ++i)
#define repeq(i, n) for(ll i=1, i##_length=(n); i<=i##_length; ++i)
#define rrep(i, n)   for(ll i=(n)-1; i>=0; --i)
#define rrepeq(i, n) for(ll i=(n)  ; i>=1; --i)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
void p() { std::cout << '\n'; }
template<typename Head, typename... Tail> void p(Head head, Tail... tail) { std::cout << head << (sizeof...(tail) ? " " : ""); p(tail...); }
template<typename T> inline void pv(std::vector<T>& v) { for(ll i=0, N=v.size(); i<N; i++) std::cout << v[i] << " \n"[i==N-1]; }
template<typename T> inline bool chmax(T& a, T b) { return a < b && (a = b, true); }
template<typename T> inline bool chmin(T& a, T b) { return a > b && (a = b, true); }
template<typename T> inline void uniq(std::vector<T>& v) { v.erase(std::unique(v.begin(), v.end()), v.end()); }
template<typename T> inline ll sz(T& v) { return v.size(); }

/*-----8<-----template-----8<-----*/

//[lib]trie木.cpp
/*
あるノードの配下の全てのノードには自身に対応する文字列に共通するプレフィックスがあり, 
ルートには空の文字列が対応している。

計算量：
　add O(|S|)
　query O(|S|)

exist は子供以下に追加された文字列の個数, 
accept はそのノードにマッチする全ての追加された文字列の番号が格納される。

Trie< char_size, margin >(): 
　文字列の種類数 char_size, 開始文字が margin のトライ木を作成する。
add(S): 文字列 S をトライ木に追加する
query(S, f, sindex): 文字列 S の sindex 文字目から一致する文字列を検索する。
　一致した文字列ごとに関数 f が呼び出される。
size(): ノード数を返す
count(): 存在する文字列の個数を返す
*/
template< ll char_size >
class TrieNode {
public:
	ll nxt[char_size];

	ll exist;
	vector< ll > accept;

	TrieNode() : exist(0) {
		memset(nxt, -1, sizeof(nxt));
	}
};
template< ll char_size, ll margin >
class Trie {
public:
	using Node = TrieNode< char_size >;

	vector< Node > nodes;
	ll root;

	Trie() : root(0) {
		nodes.push_back(Node());
	}

	void update_direct(ll node, ll id) {
		nodes[node].accept.push_back(id);
	}

	void update_child(ll node) {
		++nodes[node].exist;
	}

	void add(const string &str, ll id) {
		ll node_index = 0;
		for(ll str_index = 0; str_index < (ll)str.size(); ++str_index){
			const ll c = str[str_index] - margin;
			if(nodes[node_index].nxt[c] == -1) {
				nodes[node_index].nxt[c] = (ll) nodes.size();
				nodes.push_back(Node());
			}
			update_child(node_index);
			node_index = nodes[node_index].nxt[c];
		}
		update_direct(node_index, id);
	}

	void add(const string &str) {
		add(str, nodes[0].exist);
	}

	template<typename F>
	void query(const string &str, const F &f, ll str_index = 0) {
		ll node_index = 0;
		for(; str_index <= (ll)str.size(); ++str_index){
			for(auto&& idx : nodes[node_index].accept) f(idx);
			if(str_index == (ll)str.size())break;
			const ll c = str[str_index] - margin;
			if(nodes[node_index].nxt[c] == -1) break;
			node_index = nodes[node_index].nxt[c];
		}
	}

	ll count() const {
		return (nodes[0].exist);
	}

	ll size() const {
		return nodes.size();
	}
};

//[lib]Aho-Corasick.cpp
//[depends on]trie木.cpp
/*
イメージ図は http://algoogle.hadrori.jp/algorithm/aho-corasick.html
複数文字列に対するパターンマッチングオートマトンを構築する。
計算量 build() O(∑|Si|) Si はAho-Corasickに追加した文字列, クエリ O(1)
add(S): 文字列 S をトライ木に追加する
build(): 現在のTrieをもとにオートマトンを構築する
match(T, now): 現状態が now で, 文字列 T が現れた時に, 新たに各パターン文字列にマッチした回数を返す
move(c, now): 現状態が now で, 文字 c/文字列 T が現れたときに, 新たにパターン文字列にマッチした個数と, 次状態をpairで返す
*/
template< ll char_size, ll margin >
struct AhoCorasick : Trie< char_size + 1, margin > {
	using Trie< char_size + 1, margin >::Trie;

	const ll FAIL = char_size;
	vector< ll > correct;

	void build(bool heavy = true) {
		correct.resize(this->size());
		for(ll i = 0; i < this->size(); i++) {
			correct[i] = (ll) this->nodes[i].accept.size();
		}
		queue< ll > que;
		for(ll i = 0; i <= char_size; i++) {
			if(~this->nodes[0].nxt[i]) {
				this->nodes[this->nodes[0].nxt[i]].nxt[FAIL] = 0;
				que.emplace(this->nodes[0].nxt[i]);
			} else {
				this->nodes[0].nxt[i] = 0;
			}
		}
		while(!que.empty()) {
			auto &now = this->nodes[que.front()];
			ll fail = now.nxt[FAIL];
			correct[que.front()] += correct[fail];
			que.pop();
			for(ll i = 0; i < char_size; i++) {
				if(~now.nxt[i]) {
					this->nodes[now.nxt[i]].nxt[FAIL] = this->nodes[fail].nxt[i];
					if(heavy) {
						auto &u = this->nodes[now.nxt[i]].accept;
						auto &v = this->nodes[this->nodes[fail].nxt[i]].accept;
						vector< ll > accept;
						set_union(begin(u), end(u), begin(v), end(v), back_inserter(accept));
						u = accept;
					}
					que.emplace(now.nxt[i]);
				} else {
					now.nxt[i] = this->nodes[fail].nxt[i];
				}
			}
		}
	}

	map< ll, ll > match(const string &str, ll now = 0) {
		map< ll, ll > result;
		for(auto &c : str) {
			now = this->nodes[now].nxt[c - margin];
			for(auto &v : this->nodes[now].accept) result[v] += 1;
		}
		return result;
	}

	pair< ll, ll > move(const char &c, ll now = 0) {
		now = this->nodes[now].nxt[c - margin];
		return {correct[now], now};
	}

	pair< ll, ll > move(const string &str, ll now = 0) {
		ll sum = 0;
		for(auto &c : str) {
			auto nxt = move(c, now);
			sum += nxt.first;
			now = nxt.second;
		}
		return {sum, now};
	}
};

/*-----8<-----library-----8<-----*/

void solve() {
	while (1) {
		ll H, W;
		cin >> H >> W;
		if (H == 0 && W == 0) break;
		vector<string> S(H);
		rep(i, H) cin >> S[i];
		ll N;
		cin >> N;
		AhoCorasick<26,'A'> aho;
		rep(i,N){
			string a;
			cin >> a;
			aho.add(a);
		}
		aho.build();

		vector<char> v{'D','R','U','L'};
		
		ll start = -1, goal = -1;
		rep(i, H) rep(j, W) {
			if(S[i][j]=='S'){
				start = i * W + j;
			}
			if(S[i][j]=='G'){
				goal = i * W + j;
			}
		}

		queue<array<ll,3>> que;
		vector<map<ll, ll>> seen(H * W);
		array<ll,3> startpos = {start/W, start%W};
		que.push(startpos);
		seen[start][0] = 0;

		while(!que.empty()) {
			auto [x, y, pos] = que.front();
			que.pop();
			rep(k, 4) {
				ll nx = dx[k] + x;
				ll ny = dy[k] + y;
				if(nx <= -1 || ny <= -1 || nx >= H || ny >= W) continue;
				if(S[nx][ny] == '#') continue;
				
				//seen[nx][ny]の書き換えはここでやること
				auto [count, nextpos] = aho.move(v[k], pos);
				if (count) continue;
				ll tmp = INF;
				auto it = seen[nx * W + ny].find(nextpos);
				if (it != seen[nx * W + ny].end()){
					tmp = seen[nx * W + ny][nextpos];
				}
				if (tmp > seen[x * W + y][pos] + 1) {
					seen[nx * W + ny][nextpos] = seen[x * W + y][pos] + 1;
					que.push({nx, ny, nextpos});
				}
			}
		}

		ll ans = INF;
		for (auto&& t : seen[goal]) {
			chmin(ans, t.second);
		}
		if (ans == INF) ans = -1;
		p(ans);
	}
}

signed main() {
	std::cin.tie(nullptr);
	std::ios::sync_with_stdio(false);
	//ll Q; cin >> Q; while(Q--)solve();
	solve();
	return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 9476
final_rank: 12

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define REP(i, n) for (int i=0; i<(n); ++i)
#define RREP(i, n) for (int i=(int)(n)-1; i>=0; --i)
#define FOR(i, a, n) for (int i=(a); i<(n); ++i)
#define RFOR(i, a, n) for (int i=(int)(n)-1; i>=(a); --i)

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()

#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl
#define DEBUG(x) cerr<<#x<<" = "<<(x)<<" (L"<<__LINE__<<")"<<endl;

template<class T>
ostream &operator<<(ostream &os, const vector <T> &v) {
    os << "[";
    REP(i, SZ(v)) {
        if (i) os << ", ";
        os << v[i];
    }
    return os << "]";
}

template<class T, class U>
ostream &operator<<(ostream &os, const pair <T, U> &p) {
    return os << "(" << p.first << " " << p.second << ")";
}

template<class T>
bool chmax(T &a, const T &b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}

using ll = long long;
using ull = unsigned long long;
using ld = long double;
using P = pair<int, int>;
using vi = vector<int>;
using vll = vector<ll>;
using vvi = vector<vi>;
using vvll = vector<vll>;

const ll MOD = 1e9 + 7;
const int INF = INT_MAX / 2;
const ll LINF = LLONG_MAX / 2;
const ld eps = 1e-9;


template<int m>
struct mint {
    int x;

    mint(int x = 0) : x(((x % m) + m) % m) {}

    mint operator-() { return x ? m - x : 0; }

    mint &operator+=(mint r) {
        if ((x += r.x) >= m) x -= m;
        return *this;
    }

    mint &operator-=(mint r) {
        if ((x -= r.x) < 0) x += m;
        return *this;
    }

    mint &operator*=(mint r) {
        x = ((ll) x * r.x) % m;
        return *this;
    }

    mint inv() {
        int a = x, b = m, u = 1, v = 0, t;
        while (b > 0) {
            t = a / b;
            swap(a -= t * b, b);
            swap(u -= t * v, v);
        }
        return u;
    }

    mint &operator/=(mint r) { return *this *= r.inv(); }

    friend mint operator+(mint l, mint r) { return l += r; }

    friend mint operator-(mint l, mint r) { return l -= r; }

    friend mint operator*(mint l, mint r) { return l *= r; }

    friend mint operator/(mint l, mint r) { return l /= r; }

    mint pow(ll n) {
        mint ret = 1, tmp = *this;
        while (n) {
            if (n & 1) ret *= tmp;
            tmp *= tmp, n >>= 1;
        }
        return ret;
    }

    friend bool operator==(mint l, mint r) { return l.x == r.x; }

    friend bool operator!=(mint l, mint r) { return l.x != r.x; }

    friend ostream &operator<<(ostream &os, mint a) {
        return os << a.x;
    }

    friend istream &operator>>(istream &is, mint &a) {
        int x;
        is >> x;
        a = x;
        return is;
    }
};


template<typename T>
struct Combination {
    int _n = 1;
    vector<T> _fact{1}, _rfact{1};

    void extend(int n) {
        if (n <= _n) return;
        _fact.resize(n);
        _rfact.resize(n);
        for (int i = _n; i < n; ++i) _fact[i] = _fact[i - 1] * i;
        _rfact[n - 1] = 1 / _fact[n - 1];
        for (int i = n - 1; i > _n; --i) _rfact[i - 1] = _rfact[i] * i;
        _n = n;
    }

    T fact(int k) {
        extend(k + 1);
        return _fact.at(k);
    }

    T rfact(int k) {
        extend(k + 1);
        return _rfact.at(k);
    }

    T P(int n, int r) {
        if (r < 0 or n < r) return 0;
        return fact(n) * rfact(n - r);
    }

    T C(int n, int r) {
        if (r < 0 or n < r) return 0;
        return fact(n) * rfact(r) * rfact(n - r);
    }

    T H(int n, int r) {
        return (n == 0 and r == 0) ? 1 : C(n + r - 1, r);
    }
};

/**
 * Trie
 * @tparam char_size 文字の種類数. ASCIIで連続していること.
 * @tparam margin 0番目の文字 (e.g. 'a')
 * @usage
 * AhoCorasick PMA(26,'a');
 * PMA.add("pattern");
 * int now = root;
 * string s;
 * for (char c : s) {
 *     while (PMA.nodes[now].nxt[c - margin] == -1) {
 *         now = PMA.nodes[now].nxt[FAIL];
 *     }
 *     now = PMA.nodes[now].nxt[c - margin];
 *     // nowはsをcまで読んだときのノード.
 *     // ここでPMA.nodes[now].acceptとかを利用していろいろやる
 * }
 */
template<int char_size, int margin>
struct AhoCorasick {
    const int root = 0, FAIL = char_size;
    /**
     * nxt[FAIL]:
     *   次の文字がcのときに nxt[c - margin] == -1 であった場合,
     *   nodes[nxt[FAIL]][c - margin]に進む
     */
    struct Node {
        vector<int> nxt, accept;
        Node() : nxt(char_size + 1, -1) {}
    };
    vector<Node> nodes = {Node()};

    /**
     * @brief パターンの追加 O(|s|)
     * @param s 追加するパターン
     * @param id パターンのid. sの終端に対応するノードのacceptに追加される.
     */
    void add(const string& s, int id = 0) {
        int now = root;
        for (char c : s) {
            if (nodes[now].nxt[c - margin] == -1) {
                nodes[now].nxt[c - margin] = nodes.size();
                nodes.push_back(Node());
            }
            now = nodes[now].nxt[c - margin];
        }
        nodes[now].accept.push_back(id);
    }

    /**
     * @brief PMAの構築.
     * 構築後, 文字列sの終点に対応するNodeには
     * sのsuffixにマッチするパターンのidが格納される
     */
    void build() {
        queue<int> que;
        for (int i = 0; i < char_size; ++i) {
            if (nodes[root].nxt[i] == -1) {
                nodes[root].nxt[i] = root;
            } else {
                que.push(nodes[root].nxt[i]);
                nodes[nodes[root].nxt[i]].nxt[FAIL] = root;
            }
        }
        while (!que.empty()) {
            int now = que.front(); que.pop();
            for (int i = 0; i < char_size; ++i) {
                if (nodes[now].nxt[i] == -1) continue;
                int fail = nodes[now].nxt[FAIL];
                while (nodes[fail].nxt[i] == -1) {
                    fail = nodes[fail].nxt[FAIL];
                }
                nodes[nodes[now].nxt[i]].nxt[FAIL] = nodes[fail].nxt[i];
                auto &u = nodes[nodes[now].nxt[i]].accept;
                auto &v = nodes[nodes[fail].nxt[i]].accept;
                vector<int> accept;
                set_union(u.begin(), u.end(), v.begin(), v.end(),
                          back_inserter(accept));
                u = accept;
                que.push(nodes[now].nxt[i]);
            }
        }
    }

    friend ostream& operator<<(ostream& os, const AhoCorasick& pma) {
        const int n = pma.nodes.size();
        vector<bool> used(n);
        function<void(int)> dfs = [&](int now) {
            used[now] = true;
            os << "{" << now << " " << "#:" << pma[now].nxt[pma.FAIL];
            for (int i = 0; i < char_size; ++i) {
                int nxt = pma[now].nxt[i];
                if (nxt != -1) {
                    os << ", " << (char)(i + margin) << ":";
                    if (!used[nxt]) dfs(nxt);
                    else os << nxt;
                }
            }
            os << "}";
        };
        dfs(pma.root);
        return os;
    }
};

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    map<char,int> dy, dx;
    dy['U'] = -1, dy['R'] = 0, dy['D'] = 1, dy['L'] = 0;
    dx['U'] = 0, dx['R'] = 1, dx['D'] = 0, dx['L'] = -1;

    while (true) {
        int n, m; cin >> n >> m;
        if (n == 0) break;
        vector<string> board(n);
        int si, sj;
        for (int i = 0; i < n; ++i) {
            cin >> board[i];
            for (int j = 0; j < m; ++j) {
                if (board[i][j] == 'S') {
                    si = i, sj = j;
                }
            }
        }

        AhoCorasick<26,'A'> pma;
        int P; cin >> P;
        for (int i = 0; i < P; ++i) {
            string p; cin >> p;
            pma.add(p, i);
        }
        pma.build();

        queue<tuple<int,int,int,int>> que;
        que.emplace(si, sj, 0, pma.root);
        map<tuple<int,int,int>,bool> used;
        used[make_tuple(si, sj, pma.root)] = true;

        int ans = -1;

        while (!que.empty()) {
            int i, j, d, now;
            tie(i, j, d, now) = que.front(); que.pop();
            if (board[i][j] == 'G') {
                ans = d;
                break;
            }
            for (char dir : { 'U', 'R', 'D', 'L' }) {
                int tmp = now;
                int y = i + dy[dir], x = j + dx[dir];
                if (y < 0 or n <= y or x < 0 or m <= x or
                    board[y][x] == '#') continue;

                while (pma.nodes[tmp].nxt[dir - 'A'] == -1) {
                    tmp = pma.nodes[tmp].nxt[pma.FAIL];
                }
                tmp = pma.nodes[tmp].nxt[dir - 'A'];
                if (!pma.nodes[tmp].accept.empty()) {
                    continue;
                }
                if (!used.count(make_tuple(y, x, tmp))) {
                    used[make_tuple(y, x, tmp)] = true;
                    que.emplace(y, x, d + 1, tmp);
                }
            }
        }

        cout << ans << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 9172
final_rank: 14

code_snippet: #define MOD_TYPE 1

#pragma region Macros

#include <bits/stdc++.h>
using namespace std;

#if 0
#include <boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
using Int = boost::multiprecision::cpp_int;
using lld = boost::multiprecision::cpp_dec_float_100;
#endif
#if 1
#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#endif
using ll = long long int;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using pld = pair<ld, ld>;
template <typename Q_type>
using smaller_queue = priority_queue<Q_type, vector<Q_type>, greater<Q_type>>;

constexpr ll MOD = (MOD_TYPE == 1 ? (ll)(1e9 + 7) : 998244353);
//constexpr ll MOD = 1;
constexpr int INF = (int)1e9 + 10;
constexpr ll LINF = (ll)4e18;
constexpr double PI = acos(-1.0);
constexpr double EPS = 1e-9;
constexpr int Dx[] = {0, 0, -1, 1, -1, 1, -1, 1, 0};
constexpr int Dy[] = {1, -1, 0, 0, -1, -1, 1, 1, 0};

#define REP(i, m, n) for (ll i = m; i < (ll)(n); ++i)
#define rep(i, n) REP(i, 0, n)
#define REPI(i, m, n) for (int i = m; i < (int)(n); ++i)
#define repi(i, n) REPI(i, 0, n)
#define MP make_pair
#define MT make_tuple
#define YES(n) cout << ((n) ? "YES" : "NO") << "\n"
#define Yes(n) cout << ((n) ? "Yes" : "No") << "\n"
#define possible(n) cout << ((n) ? "possible" : "impossible") << "\n"
#define Possible(n) cout << ((n) ? "Possible" : "Impossible") << "\n"
#define Yay(n) cout << ((n) ? "Yay!" : ":(") << "\n"
#define all(v) v.begin(), v.end()
#define NP(v) next_permutation(all(v))
#define dbg(x) cerr << #x << ":" << x << "\n";

struct io_init
{
  io_init()
  {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(30) << setiosflags(ios::fixed);
  };
} io_init;
template <typename T>
inline bool chmin(T &a, T b)
{
  if (a > b)
  {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
inline bool chmax(T &a, T b)
{
  if (a < b)
  {
    a = b;
    return true;
  }
  return false;
}
inline ll CEIL(ll a, ll b)
{
  return (a + b - 1) / b;
}
template <typename A, size_t N, typename T>
inline void Fill(A (&array)[N], const T &val)
{
  fill((T *)array, (T *)(array + N), val);
}
template <typename T, typename U>
constexpr istream &operator>>(istream &is, pair<T, U> &p) noexcept
{
  is >> p.first >> p.second;
  return is;
}
template <typename T, typename U>
constexpr ostream &operator<<(ostream &os, pair<T, U> &p) noexcept
{
  os << p.first << " " << p.second;
  return os;
}
#pragma endregion

template <char MIN_CHAR = 'a', int ALPHABET = 26>
struct AhoCorasick
{
  struct node
  {
    // suff : 先頭の文字を最小限消してグラフに存在する頂点にするときの行先の頂点
    // dict : 先頭の文字を最小限消して辞書に存在する単語にするときの行先の頂点
    // depth : Trie木における深さ（省略可能）
    // word_index : このノードで終わる根からの単語のindex（祖先は含まない。なければ-1）
    // word_count : このノードで終わる単語の総数 count_total_matches()で使用
    // link : Trie及びsuffixの辺の接続先頂点（なければ-1）
    int suff = -1, dict = -1, depth = 0;
    int word_index = -1, word_count = 0;
    int link[ALPHABET];
    node() { fill(link, link + ALPHABET, -1); }
    int &operator[](char c) { return link[c - MIN_CHAR]; }
  };

  // nodes : 頂点集合
  // W : 現在の単語数
  // word_location : 各単語の（単語リストの）index
  // word_indices_by_depth : 単語のindexをdepthの降順に並べたもの
  // defer : 各単語のTrie木の最後の頂点のindex
  vector<node> nodes;
  int W;
  vector<int> word_location;
  vector<int> word_indices_by_depth;
  vector<int> defer;

  AhoCorasick(const vector<string> &words = {})
  {
    build(words);
  }

  // suffixを親とする木の隣接リスト これの上でDPやクエリ処理を行うことが多い
  vector<vector<int>> build_suffix_adj() const
  {
    vector<vector<int>> adj(nodes.size());
    for (int i = 1; i < int(nodes.size()); i++)
      adj[nodes[i].suff].push_back(i);
    return adj;
  }

  int get_or_add_child(int current, char c)
  {
    if (nodes[current][c] >= 0)
      return nodes[current][c];
    int index = int(nodes.size());
    nodes[current][c] = index;
    nodes.emplace_back();
    nodes.back().depth = nodes[current].depth + 1;
    return index;
  }

  int add_word(const string &word, int word_index)
  {
    assert(!nodes.empty());
    int current = 0;
    for (char c : word)
      current = get_or_add_child(current, c);
    if (nodes[current].word_index < 0)
      nodes[current].word_index = word_index;
    nodes[current].word_count++;
    return current;
  }

  // locationからcを追加したときの行き先 O(1)
  int get_suffix_link(int location, char c) const
  {
    if (location >= 0)
      location = nodes[location].link[c - MIN_CHAR];
    return max(location, 0);
  }

  void build(const vector<string> &words)
  {
    nodes = {node()};
    W = int(words.size());
    word_location.resize(W);
    defer.resize(W);
    int max_depth = 0;

    for (int i = 0; i < W; i++)
    {
      word_location[i] = add_word(words[i], i);
      max_depth = max(max_depth, int(words[i].size()));
      defer[i] = nodes[word_location[i]].word_index;
    }

    // depthの降順に単語indexのリストを作成
    word_indices_by_depth.resize(W);
    vector<int> depth_freq(max_depth + 1, 0);

    for (int i = 0; i < W; i++)
      depth_freq[words[i].size()]++;

    for (int i = max_depth - 1; i >= 0; i--)
      depth_freq[i] += depth_freq[i + 1];

    for (int i = 0; i < W; i++)
      word_indices_by_depth[--depth_freq[words[i].size()]] = i;

    // depth順のBFSでsuffix parentを求める
    vector<int> q = {0};

    for (int i = 0; i < int(q.size()); i++)
    {
      int current = q[i];

      for (char c = MIN_CHAR; c < MIN_CHAR + ALPHABET; c++)
      {
        int &index = nodes[current][c];
        if (index >= 0)
        {
          // currentのsuffix parentで子cを持つものが見つかるまで走査して
          // indexのsuffix parentを見つける
          int suffix_parent = get_suffix_link(nodes[current].suff, c);
          nodes[index].suff = suffix_parent;
          nodes[index].word_count += nodes[suffix_parent].word_count;
          nodes[index].dict = nodes[suffix_parent].word_index < 0 ? nodes[suffix_parent].dict : suffix_parent;
          q.push_back(index);
        }
        else
        {
          index = get_suffix_link(nodes[current].suff, c);
        }
      }
    }
  }

  // 辞書内のそれぞれの単語がtextに何個含まれているか O(text length + num words)
  vector<int> count_matches(const string &text) const
  {
    vector<int> matches(W, 0);
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      int dict_node = nodes[current].word_index < 0 ? nodes[current].dict : current;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index]++;
    }

    // depthの降順に見る
    for (int word_index : word_indices_by_depth)
    {
      int location = word_location[word_index];
      int dict_node = nodes[location].dict;

      if (dict_node >= 0)
        matches[nodes[dict_node].word_index] += matches[word_index];
    }

    for (int i = 0; i < W; i++)
      matches[i] = matches[defer[i]];

    return matches;
  }

  // textに含まれる辞書内の単語で、textのi文字目で終わるものの個数 O(text length)
  vector<int> count_matches_by_position(const string &text) const
  {
    vector<int> matches(text.size());
    int current = 0;

    for (int i = 0; i < int(text.size()); i++)
    {
      current = get_suffix_link(current, text[i]);
      matches[i] = nodes[current].word_count;
    }

    return matches;
  }

  // textに辞書内の単語が合計何個含まれているか O(text length)
  int64_t count_total_matches(const string &text) const
  {
    int64_t matches = 0;
    int current = 0;

    for (char c : text)
    {
      current = get_suffix_link(current, c);
      matches += nodes[current].word_count;
    }

    return matches;
  }
};

map<char, char> tran;

int dp[50][50][110];

void solve()
{
  int n, m;
  cin >> n >> m;
  if (n == 0 and m == 0)
    exit(0);
  vector<string> s(n);
  rep(i, n) cin >> s[i];

  int p;
  cin >> p;
  vector<string> ban(p);
  rep(i, p)
  {
    cin >> ban[i];
    for (auto &&c : ban[i])
      c = tran[c];
  }

  AhoCorasick<'0', 4> aho(ban);
  int si, sj, gi, gj;
  rep(i, n) rep(j, m)
  {
    if (s[i][j] == 'S')
      si = i, sj = j;
    if (s[i][j] == 'G')
      gi = i, gj = j;
  }
  queue<tuple<int, int, int>> que;
  que.push({si, sj, 0});
  rep(i, n) rep(j, m) rep(state, aho.nodes.size()) dp[i][j][state] = -1;
  dp[si][sj][0] = 0;

  while (!que.empty())
  {
    auto [i, j, state] = que.front();
    que.pop();

    // 左
    if (j > 0)
    {
      int next_state = aho.get_suffix_link(state, '0');
      if (!aho.nodes[next_state].word_count and dp[i][j - 1][next_state] == -1 and s[i][j - 1] != '#')
      {
        dp[i][j - 1][next_state] = dp[i][j][state] + 1;
        que.push({i, j - 1, next_state});
      }
    }

    // 右
    if (j < m - 1)
    {
      int next_state = aho.get_suffix_link(state, '1');
      if (!aho.nodes[next_state].word_count and dp[i][j + 1][next_state] == -1 and s[i][j + 1] != '#')
      {

        dp[i][j + 1][next_state] = dp[i][j][state] + 1;
        que.push({i, j + 1, next_state});
      }
    }

    // 上
    if (i > 0)
    {
      int next_state = aho.get_suffix_link(state, '2');
      if (!aho.nodes[next_state].word_count and dp[i - 1][j][next_state] == -1 and s[i - 1][j] != '#')
      {
        dp[i - 1][j][next_state] = dp[i][j][state] + 1;
        que.push({i - 1, j, next_state});
      }
    }

    // 下
    if (i < n - 1)
    {
      int next_state = aho.get_suffix_link(state, '3');
      if (!aho.nodes[next_state].word_count and dp[i + 1][j][next_state] == -1 and s[i + 1][j] != '#')
      {
        dp[i + 1][j][next_state] = dp[i][j][state] + 1;
        que.push({i + 1, j, next_state});
      }
    }
  }

  int Min = INF;
  rep(state, aho.nodes.size())
  {
    if (~dp[gi][gj][state])
      chmin(Min, dp[gi][gj][state]);
  }
  cout << (Min == INF ? -1 : Min) << "\n";
}

int main()
{
  tran['L'] = '0';
  tran['R'] = '1';
  tran['U'] = '2';
  tran['D'] = '3';
  while (1)
  {
    solve();
  }
}
accuracy: 1
time_ms: 10
memory_kb: 4268
final_rank: 4

code_snippet: #include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 55
#define maxp 105
struct node
{
    int x, y, s, d;
    node() {}
    node(int x, int y, int s, int d) : x(x), y(y), s(s), d(d) {}
};
int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, 1, -1};
int N, M, P, sx, sy, tx, ty, ns, id['Z' + 1];
int trie[maxp][4], fail[maxp], flag[maxp], used[maxn][maxn][maxp];
char mat[maxn][maxn];

void insert(char *s)
{
    int len = strlen(s), p = 0;
    for (int i = 0; i < len; i++)
    {
        int c = id[s[i]];
        if (!trie[p][c])
        {
            memset(trie[ns], 0, sizeof(trie[ns]));
            trie[p][c] = ns++;
        }
        p = trie[p][c];
    }
    flag[p] = 1;
}

void getFail()
{
    queue<int> q;
    for (int i = 0; i < 4; i++)
    {
        if (trie[0][i])
        {
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }
    while (!q.empty())
    {
        int p = q.front();
        q.pop();
        if (flag[fail[p]])
        {
            flag[p] = 1;
        }
        for (int i = 0; i < 4; i++)
        {
            if (trie[p][i])
            {
                fail[trie[p][i]] = trie[fail[p]][i];
                q.push(trie[p][i]);
            }
            else
            {
                trie[p][i] = trie[fail[p]][i];
            }
        }
    }
}

int main()
{
    id['U'] = 0, id['D'] = 1, id['R'] = 2, id['L'] = 3;
    while (~scanf("%d%d", &N, &M) && (N | M))
    {
        for (int i = 0; i < N; i++)
        {
            scanf(" %s", mat[i]);
            for (int j = 0; j < M; j++)
            {
                if (mat[i][j] == 'S')
                {
                    sx = i, sy = j;
                }
                if (mat[i][j] == 'G')
                {
                    tx = i, ty = j;
                }
            }
        }
        scanf("%d", &P);
        ns = 1;
        memset(flag, 0, sizeof(flag));
        memset(trie[0], 0, sizeof(trie[0]));
        for (int i = 0; i < P; i++)
        {
            char s[15];
            scanf(" %s", s);
            insert(s);
        }
        getFail();
        int res = inf;
        queue<node> q;
        q.push(node(sx, sy, 0, 0));
        memset(used, 0, sizeof(used));
        while (!q.empty())
        {
            node p = q.front();
            q.pop();
            int x = p.x, y = p.y, s = p.s, d = p.d;
            if (x == tx && y == ty)
            {
                res = d;
                break;
            }
            if (used[x][y][s])
            {
                continue;
            }
            used[x][y][s] = 1;
            for (int i = 0; i < 4; i++)
            {
                if (flag[trie[s][i]])
                {
                    continue;
                }
                int nx = x + dx[i], ny = y + dy[i];
                if (nx >= 0 && nx < N && ny >= 0 && ny < M && mat[nx][ny] != '#')
                {
                    q.push(node(nx, ny, trie[s][i], d + 1));
                }
            }
        }
        printf("%d\n", res == inf ? -1 : res);
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4132
final_rank: 2

code_snippet: #include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
using namespace std;
typedef pair<int, int> P;
int n, m, p, K, ans;
const char UDLR[4] = {'U', 'D', 'L', 'R'};
const int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
char map[52][52], tmp[15];
string patterns[15];
vector<string> pfx;
int next_state[150][4], map_state[52][52][150]; 
bool ng[150];
queue< P > que;


bool check(int x, int y){
    return x>=0&&x<n&&y>=0&&y<m&&map[x][y]!='#';
}


void bfs(){
    memset(map_state, 255, sizeof(map_state));
    int sx, sy, ex, ey;
    for(int i=0; i<n; i++)
    for(int j=0; j<m; j++)
        switch (map[i][j]){
            case 'S':
                sx = i;
                sy = j;
                break;
            case 'G':
                ex = i;
                ey = j;
                break; 
            default:
                break;
        }

    while(!que.empty()) que.pop();
    map_state[sx][sy][0] = 0;
    que.push(P(sx*m+sy, 0));

    bool reach=false;
    int tx, ty, tk, xx, yy, kk;
    ans = -1;
    while(!que.empty()){
        tx = que.front().first / m; ty = que.front().first % m; tk = que.front().second; 
        que.pop();
        for(int i=0; i<4; i++){
            kk = next_state[tk][i];
            if(!ng[kk] && check(tx+dx[i], ty+dy[i])){
                // state kk is not forbidden
                xx = tx + dx[i];
                yy = ty + dy[i];
                if(map_state[xx][yy][kk] == -1){
                    map_state[xx][yy][kk] = map_state[tx][ty][tk] + 1;
                    que.push(P(xx*m+yy, kk));
                    if(xx==ex && yy==ey){
                        reach = true;
                        ans = map_state[xx][yy][kk];
                        break;
                    }
                }
            } 
        }
        if(reach) break;
    }
    printf("%d\n", ans);
}


int main(){
    //freopen("in.txt", "r", stdin);
    int k;
    while(scanf("%d %d", &n, &m), n!=0 && m!=0){
        for(int i=0; i<n; i++)
            scanf("%s", map[i]);
        scanf("%d", &p);
        pfx.clear();
        for(int i=0; i<p; i++){
            scanf("%s", tmp);
            patterns[i].assign(tmp);
            for(int j=0; j<=patterns[i].length(); j++)
                pfx.push_back(patterns[i].substr(0, j));
        }
        pfx.push_back(string(""));
        sort(pfx.begin(), pfx.end());
        pfx.erase(unique(pfx.begin(), pfx.end()), pfx.end());
        K = pfx.size();

        for(int i=0; i<K; i++){
            ng[i] = false;
            for(int j=0; j<p; j++){
                ng[i] |= patterns[j].length()<=pfx[i].length() 
                        && pfx[i].substr(pfx[i].length()-patterns[j].length(), patterns[j].length()) == patterns[j];
            }
            for(int j=0; j<4; j++){
                string s = pfx[i] + UDLR[j];
                for(;;){
                    k = lower_bound(pfx.begin(), pfx.end(), s) - pfx.begin();
                    if(k<K && pfx[k]==s) break;
                    s = s.substr(1);
                }
                next_state[i][j] = k;
            }
        }

        bfs();
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4448
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<class T>
bool chmax(T& a, const T& b) {
    if (a < b) { a = b; return true; }
    return false;
}
template<class T>
bool chmin(T& a, const T& b) {
    if (b < a) { a = b; return true; }
    return false;
}

// std::vector Declaration
template<typename T>
vector<T> make_v(size_t a) { return vector<T>(a); }
template<typename T, typename... Ts>
auto make_v(size_t a, Ts... ts) {
    return vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}

// std::vector Declaration and Initialization
template<typename T>
vector<T> make_vector(size_t a, T x) { return vector<T>(a, x); }
template<typename T, typename U, typename... Ts>
auto make_vector(size_t a, U b, Ts... ts) {
    return vector<decltype(make_vector<T>(b,ts...))>(a, make_vector<T>(b, ts...));
}

// std::vector Input
template<typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (auto &e : v) is >> e;
    return is;
}

// std::vector Debug
template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "[";
    bool a = 1;
    for (auto e : v) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::array Debug
template<typename T, size_t n>
ostream& operator<<(ostream& os, const array<T, n>& v) {
    os << "[";
    bool a = 1;
    for (auto e : v) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::deque Debug
template<typename T>
ostream& operator<<(ostream& os, const deque<T>& d) {
    os << "[";
    bool a = 1;
    for (auto e : d) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::pair Debug
template<typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << "(" << p.first << " " << p.second << ")";
    return os;
}

// std::set Debug
template<typename T>
ostream& operator<<(ostream& os, const set<T>& st) {
    os << "{";
    bool a = 1;
    for (auto e : st) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "}";
    return os;
}

// std::multiset Debug
template<typename T>
ostream& operator<<(ostream& os, const multiset<T>& st) {
    os << "{";
    bool a = 1;
    for (auto e : st) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "}";
    return os;
}

// std::map Debug
template<typename T, typename U>
ostream& operator<<(ostream& os, const map<T, U>& mp) {
    os << "{";
    bool a = 1;
    for (auto e : mp) {
        os << (a ? "" : " ");
        os << e.first << ":" << e.second;
        a = 0;
    }
    os << "}";
    return os;
}

// std::tuple Debug
template<int N, class Tuple>
void out(ostream& os, const Tuple& t){}
template<int N, class Tuple, class H, class ...Ts>
void out(ostream& os, const Tuple& t) {
    if (N) os << " ";
    os << get<N>(t);
    out<N+1,Tuple,Ts...>(os, t);
}
template<class ...Ts>
ostream& operator<<(ostream& os, const tuple<Ts...>& t) {
    os << "(";
    out<0,tuple<Ts...>,Ts...>(os, t);
    os << ")";
    return os;
}

// Debug
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl

// Weighted edge
template<typename T>
struct edge {
    int src, to;
    T cost;

    edge() {}
    edge(int to, T cost) : src(-1), to(to), cost(cost) {}
    edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

    friend ostream& operator<<(ostream& os, const edge& e) {
        return os << "(" << e.src << "->" << e.to << ":" << e.cost << ")";
    }
};

using LL = int64_t;

#define fs first
#define sc second

const int64_t MOD = 1e9+7;

template<int char_size, int margin>
struct Trie {
    struct Node {
        vector<Node*> next;
        vector<int> accept;
        int depth;
        Node(int depth) : next(char_size, nullptr), depth(depth) {}
        friend ostream& operator<<(ostream& os, const Node* t) {
            os << "{";
            bool a = 0;
            for (int i = 0; i < char_size; ++i) {
                if (t->next[i] == nullptr) continue;
                if (a) os << ", "; a = 1;
                os << (char)(i + margin);
                if (t->next[i]->depth > t->depth) os << ": " << t->next[i];
            }
            return os << "}";
        }
    };

    Node* root;
    Trie() { root = new Node(0); }

    void add(const string& s, int id = 0) {
        Node* now = root;
        for (char c : s) {
            if (now->next[c - margin] == nullptr) {
                now->next[c - margin] = new Node(now->depth + 1);
            }
            now = now->next[c - margin];
        }
        now->accept.push_back(id);
    }

    friend ostream& operator<<(ostream& os, const Trie& t) {
        return os << t.root;
    }
};

template<int char_size, int margin>
struct AhoCorasick {
    Trie<char_size + 1, margin> trie;
    const int FAIL = char_size;

    AhoCorasick() : trie() {}

    void add(const string& s, int id = 0) {
        trie.add(s, id);
    }

    using Node = typename Trie<char_size + 1, margin>::Node;

    void build() {
        queue<Node*> que;
        for (int i = 0; i < char_size; ++i) {
            if (trie.root->next[i]) {
                que.push(trie.root->next[i]);
                trie.root->next[i]->next[FAIL] = trie.root;
            } else {
                trie.root->next[i] = trie.root;
            }
        }
        while (!que.empty()) {
            Node* now = que.front(); que.pop();
            for (int i = 0; i < char_size; ++i) {
                if (now->next[i] == nullptr) continue;
                Node* fail = now->next[FAIL];
                while (fail->next[i] == nullptr) {
                    fail = fail->next[FAIL];
                }
                now->next[i]->next[FAIL] = fail->next[i];
                auto &u = now->next[i]->accept;
                auto &v = fail->next[i]->accept;
                vector<int> accept;
                set_union(u.begin(), u.end(), v.begin(), v.end(),
                        back_inserter(accept));
                u = accept;
                que.push(now->next[i]);
            }
        }
    }

    map<int,int> match(const string& str) {
        map<int,int> ret;
        Node* now = trie.root;
        for (char c : str) {
            while (now->next[c - margin] == nullptr) now = now->next[FAIL];
            now = now->next[c - margin];
            for (int id : now->accept) ++ret[id];
        }
        return ret;
    }

    friend ostream& operator<<(ostream& os, const AhoCorasick& a) {
        return os << a.trie;
    }
};


int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    map<char,int> dy, dx;
    dy['U'] = -1, dy['R'] = 0, dy['D'] = 1, dy['L'] = 0;
    dx['U'] = 0, dx['R'] = 1, dx['D'] = 0, dx['L'] = -1;

    while (true) {
        int n, m; cin >> n >> m;
        if (n == 0) break;
        vector<string> board(n);
        int si, sj;
        for (int i = 0; i < n; ++i) {
            cin >> board[i];
            for (int j = 0; j < m; ++j) {
                if (board[i][j] == 'S') {
                    si = i, sj = j;
                }
            }
        }

        AhoCorasick<26,'A'> aho;
        int P; cin >> P;
        for (int i = 0; i < P; ++i) {
            string p; cin >> p;
            aho.add(p, i);
        }
        aho.build();

        using Node = AhoCorasick<26,'A'>::Node;

        queue<tuple<int,int,int,Node*>> que;
        que.emplace(si, sj, 0, aho.trie.root);
        map<tuple<int,int,Node*>,bool> used;
        used[make_tuple(si, sj, aho.trie.root)] = true;

        int ans = -1;

        while (!que.empty()) {
            int i, j, d; Node* now;
            tie(i, j, d, now) = que.front(); que.pop();
            if (board[i][j] == 'G') {
                ans = d;
                break;
            }
            for (char dir : { 'U', 'R', 'D', 'L' }) {
                Node* tmp = now;
                int y = i + dy[dir], x = j + dx[dir];
                if (y < 0 or n <= y or x < 0 or m <= x or
                        board[y][x] == '#') continue;

                while (tmp->next[dir - 'A'] == nullptr) {
                    tmp = tmp->next[26];
                }
                tmp = tmp->next[dir - 'A'];
                if (tmp->accept.size()) {
                    continue;
                }
                if (!used[make_tuple(y, x, tmp)]) {
                    used[make_tuple(y, x, tmp)] = true;
                    que.emplace(y, x, d + 1, tmp);
                }
            }
        }

        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 9792
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

template<class T>
bool chmax(T& a, const T& b) {
    if (a < b) { a = b; return true; }
    return false;
}
template<class T>
bool chmin(T& a, const T& b) {
    if (b < a) { a = b; return true; }
    return false;
}

// std::vector Declaration
template<typename T>
vector<T> make_v(size_t a) { return vector<T>(a); }
template<typename T, typename... Ts>
auto make_v(size_t a, Ts... ts) {
    return vector<decltype(make_v<T>(ts...))>(a, make_v<T>(ts...));
}

// std::vector Declaration and Initialization
template<typename T>
vector<T> make_vector(size_t a, T x) { return vector<T>(a, x); }
template<typename T, typename U, typename... Ts>
auto make_vector(size_t a, U b, Ts... ts) {
    return vector<decltype(make_vector<T>(b,ts...))>(a, make_vector<T>(b, ts...));
}

// std::vector Input
template<typename T>
istream& operator>>(istream& is, vector<T>& v) {
    for (auto &e : v) is >> e;
    return is;
}

// std::vector Debug
template<typename T>
ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "[";
    bool a = 1;
    for (auto e : v) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::array Debug
template<typename T, size_t n>
ostream& operator<<(ostream& os, const array<T, n>& v) {
    os << "[";
    bool a = 1;
    for (auto e : v) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::deque Debug
template<typename T>
ostream& operator<<(ostream& os, const deque<T>& d) {
    os << "[";
    bool a = 1;
    for (auto e : d) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "]";
    return os;
}

// std::pair Debug
template<typename T, typename U>
ostream& operator<<(ostream& os, const pair<T, U>& p) {
    os << "(" << p.first << " " << p.second << ")";
    return os;
}

// std::set Debug
template<typename T>
ostream& operator<<(ostream& os, const set<T>& st) {
    os << "{";
    bool a = 1;
    for (auto e : st) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "}";
    return os;
}

// std::multiset Debug
template<typename T>
ostream& operator<<(ostream& os, const multiset<T>& st) {
    os << "{";
    bool a = 1;
    for (auto e : st) {
        os << (a ? "" : " ");
        os << e;
        a = 0;
    }
    os << "}";
    return os;
}

// std::map Debug
template<typename T, typename U>
ostream& operator<<(ostream& os, const map<T, U>& mp) {
    os << "{";
    bool a = 1;
    for (auto e : mp) {
        os << (a ? "" : " ");
        os << e.first << ":" << e.second;
        a = 0;
    }
    os << "}";
    return os;
}

// std::tuple Debug
template<int N, class Tuple>
void out(ostream& os, const Tuple& t){}
template<int N, class Tuple, class H, class ...Ts>
void out(ostream& os, const Tuple& t) {
    if (N) os << " ";
    os << get<N>(t);
    out<N+1,Tuple,Ts...>(os, t);
}
template<class ...Ts>
ostream& operator<<(ostream& os, const tuple<Ts...>& t) {
    os << "(";
    out<0,tuple<Ts...>,Ts...>(os, t);
    os << ")";
    return os;
}

// Debug
#define DUMP(x) cerr<<#x<<" = "<<(x)<<endl

// Weighted edge
template<typename T>
struct edge {
    int src, to;
    T cost;

    edge() {}
    edge(int to, T cost) : src(-1), to(to), cost(cost) {}
    edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

    friend ostream& operator<<(ostream& os, const edge& e) {
        return os << "(" << e.src << "->" << e.to << ":" << e.cost << ")";
    }
};

using LL = int64_t;

#define fs first
#define sc second

const int64_t MOD = 1e9+7;

template<int char_size, int margin>
struct Trie {
    struct Node {
        Node* next[char_size];
        vector<int> accept;
        Node() : accept(0) {
            for (int i = 0; i < char_size; i++)
                next[i] = nullptr;
        }
    };

    Node* root;
    Trie() { root = new Node(); }

    void add(const string& s, int id = 0) {
        Node* now = root;
        for (char c : s) {
            if (now->next[c - margin] == nullptr) {
                now->next[c - margin] = new Node();
            }
            now = now->next[c - margin];
        }
        now->accept.push_back(id);
    }
};

template<int char_size, int margin>
struct AhoCorasick {
    Trie<char_size + 1, margin> trie;
    const int FAIL = char_size;

    AhoCorasick() : trie() {}

    void add(const string& s, int id = 0) {
        trie.add(s, id);
    }

    using node_t = typename Trie<char_size + 1, margin>::Node;

    void build() {
        queue<node_t*> que;
        for (int i = 0; i < char_size; ++i) {
            if (trie.root->next[i]) {
                que.push(trie.root->next[i]);
                trie.root->next[i]->next[FAIL] = trie.root;
            } else {
                trie.root->next[i] = trie.root;
            }
        }
        while (!que.empty()) {
            node_t* now = que.front(); que.pop();
            for (int i = 0; i < char_size; ++i) {
                if (now->next[i] == nullptr) continue;
                node_t* fail = now->next[FAIL];
                while (fail->next[i] == nullptr) {
                    fail = fail->next[FAIL];
                }
                now->next[i]->next[FAIL] = fail->next[i];
                auto &u = now->next[i]->accept;
                auto &v = fail->next[i]->accept;
                vector<int> accept;
                set_union(u.begin(), u.end(), v.begin(), v.end(),
                        back_inserter(accept));
                u = accept;
                que.push(now->next[i]);
            }
        }
    }

    map<int,int> match(const string& str) {
        map<int,int> ret;
        node_t* now = trie.root;
        for (char c : str) {
            while (now->next[c - margin] == nullptr) now = now->next[FAIL];
            now = now->next[c - margin];
            for (int id : now->accept) ++ret[id];
        }
        return ret;
    }
};


int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);

    map<char,int> dy, dx;
    dy['U'] = -1, dy['R'] = 0, dy['D'] = 1, dy['L'] = 0;
    dx['U'] = 0, dx['R'] = 1, dx['D'] = 0, dx['L'] = -1;

    while (true) {
        int n, m; cin >> n >> m;
        if (n == 0) break;
        vector<string> board(n);
        int si, sj;
        for (int i = 0; i < n; ++i) {
            cin >> board[i];
            for (int j = 0; j < m; ++j) {
                if (board[i][j] == 'S') {
                    si = i, sj = j;
                }
            }
        }

        AhoCorasick<26,'A'> aho;

        int P; cin >> P;
        for (int i = 0; i < P; ++i) {
            string p; cin >> p;
            aho.add(p, i);
        }

        aho.build();

        using node_t = AhoCorasick<26,'A'>::node_t;

        queue<tuple<int,int,int,node_t*>> que;
        que.emplace(si, sj, 0, aho.trie.root);
        map<tuple<int,int,node_t*>,bool> used;
        used[make_tuple(si, sj, aho.trie.root)] = true;

        int ans = -1;

        while (!que.empty()) {
            int i, j, d; node_t* now;
            tie(i, j, d, now) = que.front(); que.pop();
            if (board[i][j] == 'G') {
                ans = d;
                break;
            }
            for (char dir : { 'U', 'R', 'D', 'L' }) {
                node_t* tmp = now;
                int y = i + dy[dir], x = j + dx[dir];
                if (y < 0 or n <= y or x < 0 or m <= x or
                        board[y][x] == '#') continue;

                while (tmp->next[dir - 'A'] == nullptr) {
                    tmp = tmp->next[26];
                }
                tmp = tmp->next[dir - 'A'];
                if (tmp->accept.size()) {
                    continue;
                }
                if (!used[make_tuple(y, x, tmp)]) {
                    used[make_tuple(y, x, tmp)] = true;
                    que.emplace(y, x, d + 1, tmp);
                }
            }
        }

        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 9756
final_rank: 15

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <utility>
#include <tuple>
#define maxn 55
#define maxV 105
#define mt make_tuple

using namespace std;
typedef long long ll;
typedef tuple<int, int, int> T;
struct node{
  int chi[4], fail;
  bool forbid;
  node(){
    memset(chi, 0, sizeof(chi));
    fail = forbid = 0;
  }
}a[maxV]; int V;
// root: node 1.
namespace acAuto{
  void init(){
    for(int i = 1;i <= V;i++) a[i] = node();
    V = 1;
  }
  void ins(int* s, int n){ // |S| = n.
    int u = 1;
    for(int i = 1;i <= n;i++){
      if(!a[u].chi[s[i]]) a[u].chi[s[i]] = ++V;
      u = a[u].chi[s[i]];
    }
    a[u].forbid = true;
  }
  void build(){
    queue<int> que;
    que.push(1);
    while(!que.empty()){
      int u = que.front();
      que.pop();
      for(int i = 0;i < 4;i++){
        int v = a[u].chi[i], f = a[u].fail;
        if(v){
          if(f) a[v].fail = a[f].chi[i];
          else a[v].fail = 1;
          if(a[a[v].fail].forbid) a[v].forbid = true;
          que.push(v);
        }else{
          if(f) a[u].chi[i] = a[f].chi[i];
          else a[u].chi[i] = 1;
        }
      }
    }
  }
}
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
int idx[135], n, m, p, sidx[15], rs, cs, rg, cg;
char grid[maxn][maxn], s[15];
int f[maxn][maxn][maxV];
void solve(){
  acAuto::init();
  for(int i = 1;i <= n;i++) scanf("%s", grid[i] + 1);
  scanf("%d", &p);
  for(int i = 1;i <= p;i++){
    scanf("%s", s + 1);
    int l = strlen(s + 1);
    for(int j = 1;j <= l;j++) sidx[j] = idx[(int)s[j]];
    acAuto::ins(sidx, l);
  }
  acAuto::build();
  for(int i = 0;i <= n + 1;i++) grid[i][0] = grid[i][m + 1] = '#';
  for(int i = 1;i <= m;i++) grid[0][i] = grid[n + 1][i] = '#';
  for(int i = 1;i <= n;i++){
    for(int j = 1;j <= m;j++){
      if(grid[i][j] == 'S') rs = i, cs = j;
      else if(grid[i][j] == 'G') rg = i, cg = j;
    }
  }
  memset(f, 0x3f, sizeof(f));
  f[rs][cs][1] = 0;
  queue<T> que;
  que.push(mt(rs, cs, 1));
  while(!que.empty()){
    int x = get<0>(que.front()), y = get<1>(que.front()), u = get<2>(que.front());
    que.pop();
    if(x == rg && y == cg){
      printf("%d\n", f[x][y][u]);
      return;
    }
    for(int d = 0;d < 4;d++){
      int cx = x + dx[d], cy = y + dy[d], cu = a[u].chi[d];
      if(grid[cx][cy] != '#' && !a[cu].forbid && f[x][y][u] + 1 < f[cx][cy][cu]){
        f[cx][cy][cu] = f[x][y][u] + 1;
        que.push(mt(cx, cy, cu));
      }
    }
  }
  puts("-1");
}
int main(){
  idx['U'] = 0, idx['R'] = 1, idx['D'] = 2, idx['L'] = 3;
  while(~scanf("%d%d", &n, &m) && n) solve();
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 4564
final_rank: 8

code_snippet: #include <bits/stdc++.h>

template<class Converter, class SuffixInfo, int NODE_NUM = 1000000>
class AhoCorasick {
public:
  using value_structure = typename Converter::value_structure;
  using size_type = std::uint64_t;
  static constexpr size_type num_of_kinds = Converter::num_of_kinds;

  using value_type = typename SuffixInfo::value_type;
  using merged_value_type = typename SuffixInfo::merged_value_type;

  struct Node {
    size_type size, end, len, faillink;
    value_type val;
    merged_value_type suf_info;
    std::array<int, num_of_kinds> ch;
    Node () : size(0), end(0), len(0), val(SuffixInfo::identity()),
              suf_info(SuffixInfo::midentity()), faillink(0) { ch.fill(-1); }
  };

private:
  std::vector<Node> node;

public:
  AhoCorasick() {
    node.reserve(NODE_NUM);
    node.push_back(Node());
  }

  void insert(const value_structure& v, size_type num = 1, value_type val = value_type(), size_type k = 0, size_type idx = 0) {
    node[idx].size += num;
    if (k == v.size()) {
      node[idx].end += num;
      node[idx].val = SuffixInfo::operation(node[idx].val, val);
      return;
    }
    size_type nxt = Converter::convert(v[k]);
    if (node[idx].ch[nxt] == -1) {
      node.push_back(Node());
      node[idx].ch[nxt] = node.size()-1;
      node.back().len = k+1;
    }
    insert(v, num, val, k+1, node[idx].ch[nxt]);
  }

  size_type count_prefix(const value_structure& v, size_type k = 0, size_type idx = 0) {
    if (v.size() == k) return node[idx].size;
    size_type nxt = Converter::convert(v[k]);
    if (node[idx].ch[nxt] == -1) return 0;
    return count_prefix(v, k+1, node[idx].ch[nxt]);
  }

  size_type count(const value_structure& v, size_type k = 0, size_type idx = 0) {
    if (v.size() == k) return node[idx].end;
    size_type nxt = Converter::convert(v[k]);
    if (node[idx].ch[nxt] == -1) return 0;
    return count(v, k+1, node[idx].ch[nxt]);
  }

  template<typename F>
  void query(const value_structure& v, const F& f, size_type k = 0, size_type idx = 0) {
    if (node[idx].size > 0) f(node[idx]);
    if (v.size() == k) return;
    size_type nxt = Converter::convert(v[k]);
    if (node[idx].ch[nxt] == -1) return;
    query(v, f, k+1, node[idx].ch[nxt]);
  }

  size_type proceed(size_type k, size_type c, bool need_convert = 1) {
    if (need_convert) c = Converter::convert(c);
    while (node[k].ch[c] == -1)  k = node[k].faillink;
    return node[k].ch[c];
  }

  void build() {
    std::queue<size_type> que;
    for (int i = 0; i < num_of_kinds; i++) {
      if (node[0].ch[i] == -1) node[0].ch[i] = 0;
      else {
        que.push(node[0].ch[i]);
        SuffixInfo::merge(node[node[0].ch[i]].suf_info, node[node[0].ch[i]].val);
      }
    }
    while (que.size()) {
      int k = que.front();
      que.pop();
      for (int i = 0; i < num_of_kinds; i++) {
        if (node[k].ch[i] == -1) continue;
        size_type nx = node[k].ch[i];
        node[nx].faillink = proceed(node[k].faillink, i, false);

        SuffixInfo::merge(node[nx].suf_info, node[nx].val);
        SuffixInfo::merge(node[nx].suf_info, node[node[nx].faillink].suf_info);
        que.push(nx);
      }
    }
  }

  const Node& operator[](size_type k) {
    return node[k];
  }
};

int dy[4] = {-1, 1, 0, 0};
int dx[4] = {0, 0, -1, 1};

class Converter {
public:
  using value_structure = std::string;
  using value_type = typename value_structure::value_type;
  static constexpr std::size_t num_of_kinds = 4;
  static std::size_t convert(const value_type& v) {
    switch (v) {
      case 'U': return 0;
      case 'D': return 1;
      case 'L': return 2;
      case 'R': return 3;
    }
  }
};

class SuffixInfo {
public:
  using value_type = int;
  using merged_value_type = int;
  static value_type identity() { return 0; }
  static merged_value_type midentity() { return 0; }
  static value_type operation(const value_type& a, const value_type& b) {
    return a | b;
  }
  static void merge(merged_value_type& a, const merged_value_type& b) {
    a |= b;
  }
//  static void merge(merged_value_type& a, const value_type& b) {
//    a |= b;
//  }
};

void solve() {
  using namespace std;
  AhoCorasick<Converter, SuffixInfo> ah;
  int n, m;
  cin >> n >> m;
  if (n + m == 0) exit(0);
  vector<string> f(n);
  string dir="UDLR";
  pair<int, int> st, goal;
  for (int i = 0; i < n; i++) {
    cin >> f[i];
    for (int j = 0; j < m; j++) {
      if (f[i][j] == 'S') st = {i, j};
      if (f[i][j] == 'G') goal = {i, j};
    }
  }
  auto in = [&](int y, int x) {
    return 0<=y&&y<n&&0<=x&&x<m&&f[y][x]!='#';
  };
  int P;
  cin >> P;
  for (int i = 0; i < P; i++) {
    string s;
    cin >> s;
    ah.insert(s, 1, 1);
  }
  ah.build();
  using T = tuple<int, int, int, int>; // d, y, x, v
  vector<vector<vector<int>>> d(n, vector<vector<int>>(m, vector<int>(110, (int)1e9)));
  queue<T> que;
  que.emplace(0, st.first, st.second, 0);
  d[st.first][st.second][0] = 0;
  while (que.size()) {
    int dd, ny, nx, v;
    tie(dd, ny, nx, v) = que.front(); que.pop();
    for (int i = 0; i < 4; i++) {
      int yy = ny+dy[i], xx = nx+dx[i], vv = ah.proceed(v, dir[i]);
      if (!in(yy, xx)) continue;
      if (ah[vv].suf_info) {
        continue;
      } else {
        if (d[yy][xx][vv] > dd + 1) {
          d[yy][xx][vv] = dd + 1;
          que.emplace(dd+1, yy, xx, vv);
        }
      }
    }
  }
  int res = 1e9;
  for (int i = 0; i < 110; i++) {
    res = min(res, d[goal.first][goal.second][i]);
  }
  if (res == 1e9) {
    cout << -1 << endl;
  } else {
    cout << res << endl;
  }
}

int main(void) {
  while(1) {
    solve();
  }
}

/*
verify: https://tenka1-2016-final-open.contest.atcoder.jp/submissions/8400970

template<class Converter, class SuffixInfo>
class AhoCorasick

Converter:
	- 要求
		- value_structure: std::string, std::vectorなどの列構造
			- size, operator[] が必要

		- static constexpr std::size_t num_of_kinds
			- 現れる値の種類数

		- static convert(value_type) -> size_t
			- 値を[0, num_of_kinds)に変換する

SuffixInfo:
  - 要求
    - value_type: それぞれの文字列が持つ値の型

    - merged_value_type: suffixが一致する要素の情報をまとめたもの

    - identity -> value_type
      - value_typeの単位元（初期値）

    - midentity -> merged_value_type
      - merged_value_typeの初期値（単位元とは？？？）

    - operation(const value_type&, const value_type&)

    - merge(merged_value_type&, const value_type&)
    - merge(merged_value_type&, const merged_value_type&)


AhoCorasick
	- 提供
		- Node
			- size
				- 部分木に単語がいくつあるか

			- end
				- その頂点で終わる単語がいくつあるか

			- len
				- その頂点までで何文字あるか
			
			- ch[num_of_kinds]
				- それぞれの子のpoolでのindex(存在しなければ-1)

		- insert(value_structure v, num, k)
			- O(|v|)
			- num個のv[k..)を挿入する

		- count_prefix(value_structure v, k)
			- O(|v|)
			- v[k..)をprefixとして含むものがいくつあるか返す

		- count(value_structure v, k)
			- O(|v|)
			- v[k..)がいくつあるか返す

		- query(value_structure v, F f, k)
			- O(|v|)
			- v[k..)のprefixそれぞれについてf(node)を呼び出す

    - build

    - proceed(k, c)
      - 今いる頂点がkのとき、次の文字がcのときに進む頂点を返す
 */
accuracy: 1
time_ms: 20
memory_kb: 4148
final_rank: 5

code_snippet: #include "bits/stdc++.h"

#define REP(i, n) for (int i = 0; i < n; ++i)
// https://onlinejudge.u-aizu.ac.jp/status/users/EtoNagisa/submissions/1/2212/judge/3966278/C++14
using namespace std;

#include "bits/stdc++.h"

struct lower_alphabet {
  static constexpr std::size_t char_size = 26;
  static constexpr char min_char = 'a';
};
struct upper_alphabet {
  static constexpr std::size_t char_size = 26;
  static constexpr char min_char = 'A';
};
struct general_char {
  static constexpr std::size_t char_size = 256;
  static constexpr char min_char = 0;
};
template <typename character>
class aho_corasick {
 public:
  static constexpr std::size_t invalid_index = -1;
  struct PMA {
    std::size_t fail;  // index of state correspond to fail suffix
    std::vector<std::size_t> next, accept;
    std::set<std::size_t> r_fail;
    PMA() : fail(0), next(character::char_size, invalid_index) {}
  };
  std::vector<PMA> nodes;
  std::size_t cnt;

  aho_corasick() : cnt(0) {}
  void build(const std::vector<std::string> &dict) {
    add_node();
    for (std::size_t i = 0; i < dict.size(); ++i) {
      std::size_t now = 0;
      for (std::size_t j = 0; j < dict[i].size(); ++j) {
        std::size_t t = static_cast<size_t>(dict[i][j] - character::min_char);
        if (nodes[now].next[t] == invalid_index) {
          std::size_t next = size();
          add_node();
          nodes[now].next[t] = next;
        }
        now = nodes[now].next[t];
      }
      nodes[now].accept.push_back(i);
    }
    std::queue<std::size_t> q;
    for (std::size_t i = 0; i < character::char_size; ++i) {
      if (nodes[0].next[i] == invalid_index) {
        nodes[0].next[i] = 0;
      } else {
        set_fail(nodes[0].next[i], 0);
        q.push(nodes[0].next[i]);
      }
    }
    while (!q.empty()) {
      std::size_t p = q.front();
      q.pop();
      for (std::size_t i = 0; i < character::char_size; ++i) {
        if (nodes[p].next[i] != invalid_index) {
          std::size_t tmp = next(nodes[p].fail, i + character::min_char);
          set_fail(nodes[p].next[i], tmp);
          for (std::size_t ac : nodes[tmp].accept) {
            nodes[nodes[p].next[i]].accept.push_back(ac);
          }
          q.push(nodes[p].next[i]);
        }
      }
    }
  }
  void add(const std::string &s) {
    std::size_t start = -1, now = 0;
    for (std::size_t i = 0; i < s.size(); ++i) {
      std::size_t t = static_cast<size_t>(s[i] - character::min_char);
      if (nodes[now].next[t] == invalid_index) {
        start = i;
        break;
      }
      now = nodes[now].next[t];
    }
    for (std::size_t i = start; i < s.size(); ++i) {
      std::size_t t = static_cast<size_t>(s[i] - character::min_char);
      std::size_t nxt = size();
      add_node();
      nodes[now].next[t] = nxt;
      std::size_t tmp = next(nodes[now].fail, s[i]);
      set_fail(nxt, tmp);
      for (std::size_t ac : nodes[tmp]) {
        nodes[nxt].accept.push_back(ac);
      }

      for (std::size_t p : nodes[now].r_fail) {
        if (nodes[p].next[t] != invalid_index) {
          set_fail(nodes[p].next[t], nxt);
        }
      }
      now = nxt;
    }
  }
  std::size_t size() const { return cnt; }
  std::size_t next(std::size_t now, char c) const {
    std::size_t t = static_cast<std::size_t>(c - character::min_char);
    while (nodes[now].next[t] == invalid_index) now = nodes[now].fail;
    return nodes[now].next[t];
  }
  std::vector<std::vector<std::size_t>> match(const std::string &s) const {
    std::size_t now = 0;
    std::vector<std::vector<std::size_t>> ret(s.size());
    for (std::size_t i = 0; i < s.size(); ++i) {
      now = next(now, s[i]);
      for (auto ac : nodes[now].accept) {
        ret[i].push_back(ac);
      }
    }
  }

 private:
  void add_node() {
    nodes.emplace_back();
    cnt++;
  }
  void set_fail(std::size_t from, std::size_t to) {
    nodes[nodes[from].fail].r_fail.erase(from);
    nodes[from].fail = to;
    nodes[to].r_fail.insert(from);
  }
};
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
string mv = "DRUL";
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int n, m;
  while (cin >> n >> m, n) {
    vector<string> v(n);
    REP(i, n) cin >> v[i];
    int qu;
    cin >> qu;
    vector<string> p(qu);
    REP(i, qu) cin >> p[i];
    aho_corasick<upper_alphabet> ac;
    ac.build(p);
    int sx = -1, sy = -1, tx = -1, ty = -1;
    REP(i, n) REP(j, m) {
      if (v[i][j] == 'S') {
        sx = i;
        sy = j;
      } else if (v[i][j] == 'G') {
        tx = i;
        ty = j;
      }
    }
    int k = ac.nodes.size();
    vector<vector<vector<int>>> dp(n,
                                   vector<vector<int>>(m, vector<int>(k, 1e9)));
    dp[sx][sy][0] = 0;
    queue<pair<pair<int, int>, int>> q;
    q.push({{sx, sy}, 0});
    while (!q.empty()) {
      auto c = q.front();
      q.pop();
      int x = c.first.first, y = c.first.second, s = c.second;
      REP(d, 4) {
        int nx = x + dx[d], ny = y + dy[d], ns = ac.next(s, mv[d]);
        if (nx < 0 || nx >= n || ny < 0 || ny >= m || v[nx][ny] == '#' ||
            ac.nodes[ns].accept.size() > 0)
          continue;
        if (dp[nx][ny][ns] > dp[x][y][s] + 1) {
          dp[nx][ny][ns] = dp[x][y][s] + 1;
          q.push({{nx, ny}, ns});
        }
      }
    }
    int ans = 1e9;
    REP(i, k) ans = min(ans, dp[tx][ty][i]);
    if (ans == 1e9)
      cout << -1 << endl;
    else
      cout << ans << endl;
  }
}
accuracy: 1
time_ms: 20
memory_kb: 3800
final_rank: 1

code_snippet: #include "bits/stdc++.h"

#define REP(i, n) for (int i = 0; i < n; ++i)
// https://onlinejudge.u-aizu.ac.jp/status/users/EtoNagisa/submissions/1/2212/judge/3966278/C++14
using namespace std;

#include "bits/stdc++.h"

struct lower_alphabet {
  static constexpr std::size_t char_size = 26;
  static constexpr char min_char = 'a';
};
struct upper_alphabet {
  static constexpr std::size_t char_size = 26;
  static constexpr char min_char = 'A';
};
struct general_char {
  static constexpr std::size_t char_size = 256;
  static constexpr char min_char = 0;
};
template <typename character>
class aho_corasick {
 public:
  static constexpr std::size_t invalid_index = -1;
  struct PMA {
    std::size_t fail;  // index of state correspond to fail suffix
    std::vector<std::size_t> next, accept;
    std::set<std::size_t> r_fail;
    PMA() : fail(0), next(character::char_size, invalid_index) {}
  };
  std::vector<PMA> nodes;
  std::size_t cnt;

  aho_corasick() : cnt(0) {}
  void build(const std::vector<std::string> &dict) {
    add_node();
    for (std::size_t i = 0; i < dict.size(); ++i) {
      std::size_t now = 0;
      for (std::size_t j = 0; j < dict[i].size(); ++j) {
        std::size_t t = static_cast<size_t>(dict[i][j] - character::min_char);
        if (nodes[now].next[t] == invalid_index) {
          std::size_t next = size();
          add_node();
          nodes[now].next[t] = next;
        }
        now = nodes[now].next[t];
      }
      nodes[now].accept.push_back(i);
    }
    std::queue<std::size_t> q;
    for (std::size_t i = 0; i < character::char_size; ++i) {
      if (nodes[0].next[i] == invalid_index) {
        nodes[0].next[i] = 0;
      } else {
        set_fail(nodes[0].next[i], 0);
        q.push(nodes[0].next[i]);
      }
    }
    while (!q.empty()) {
      std::size_t p = q.front();
      q.pop();
      for (std::size_t i = 0; i < character::char_size; ++i) {
        if (nodes[p].next[i] != invalid_index) {
          std::size_t tmp = next(nodes[p].fail, i + character::min_char);
          set_fail(nodes[p].next[i], tmp);
          for (std::size_t ac : nodes[tmp].accept) {
            nodes[nodes[p].next[i]].accept.push_back(ac);
          }
          q.push(nodes[p].next[i]);
        }
      }
    }
  }

  std::size_t size() const { return cnt; }
  std::size_t next(std::size_t now, char c) const {
    std::size_t t = static_cast<std::size_t>(c - character::min_char);
    while (nodes[now].next[t] == invalid_index) now = nodes[now].fail;
    return nodes[now].next[t];
  }
  std::vector<std::vector<std::size_t>> match(const std::string &s) const {
    std::size_t now = 0;
    std::vector<std::vector<std::size_t>> ret(s.size());
    for (std::size_t i = 0; i < s.size(); ++i) {
      now = next(now, s[i]);
      for (auto ac : nodes[now].accept) {
        ret[i].push_back(ac);
      }
    }
  }

 private:
  void add_node() {
    nodes.emplace_back();
    cnt++;
  }
  void set_fail(std::size_t from, std::size_t to) {
    nodes[nodes[from].fail].r_fail.erase(from);
    nodes[from].fail = to;
    nodes[to].r_fail.insert(from);
  }
};
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
string mv = "DRUL";
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int n, m;
  while (cin >> n >> m, n) {
    vector<string> v(n);
    REP(i, n) cin >> v[i];
    int qu;
    cin >> qu;
    vector<string> p(qu);
    REP(i, qu) cin >> p[i];
    aho_corasick<upper_alphabet> ac;
    ac.build(p);
    int sx = -1, sy = -1, tx = -1, ty = -1;
    REP(i, n) REP(j, m) {
      if (v[i][j] == 'S') {
        sx = i;
        sy = j;
      } else if (v[i][j] == 'G') {
        tx = i;
        ty = j;
      }
    }
    int k = ac.nodes.size();
    vector<vector<vector<int>>> dp(n,
                                   vector<vector<int>>(m, vector<int>(k, 1e9)));
    dp[sx][sy][0] = 0;
    queue<pair<pair<int, int>, int>> q;
    q.push({{sx, sy}, 0});
    while (!q.empty()) {
      auto c = q.front();
      q.pop();
      int x = c.first.first, y = c.first.second, s = c.second;
      REP(d, 4) {
        int nx = x + dx[d], ny = y + dy[d], ns = ac.next(s, mv[d]);
        if (nx < 0 || nx >= n || ny < 0 || ny >= m || v[nx][ny] == '#' ||
            ac.nodes[ns].accept.size() > 0)
          continue;
        if (dp[nx][ny][ns] > dp[x][y][s] + 1) {
          dp[nx][ny][ns] = dp[x][y][s] + 1;
          q.push({{nx, ny}, ns});
        }
      }
    }
    int ans = 1e9;
    REP(i, k) ans = min(ans, dp[tx][ty][i]);
    if (ans == 1e9)
      cout << -1 << endl;
    else
      cout << ans << endl;
  }
}
accuracy: 1
time_ms: 30
memory_kb: 3868
final_rank: 3