#include <cstdio>
#include <vector>
#include <stack>
#include <iostream>
#include <string>
#include <tuple>
#include <random>
#include <map>
#include <queue>
#include <set>
#include <complex>
#include <algorithm>
#include <cassert>
#include <iterator>
#include <numeric>

using namespace std;

typedef long double ld;
typedef long long ll;
typedef pair<ll, ll> P;

const ll INF = 1e15;
const double eps = 1e-6;

// Aho-Corasick 法
/*
* 複数パターン検索を行う．
* パターン文字列の長さの和&L&，検索文字列の長さ$M$のとき
* PMA構築に$\mathcal{O}(L)$，検索に$\mathcal{O}(L+N)$かかる．
* - verified by : UVa 10679
*/

struct PMAnode {
	PMAnode * next[256];
	PMAnode * fail;
	vector<int> accept;
	int id;
	PMAnode(int id_) { fill(next, next + 256, nullptr); id = id_; }
	PMAnode() { fill(next, next + 256, nullptr); id = 0; }
};
// Aho Corasick
struct PMA {
	PMAnode root;
	int n_pat; // number of patterns
	vector<PMAnode*> idto;
	PMA(vector<string> &ps) { // パターン文字列を与える
		int id = 1;
		n_pat = ps.size();
		idto.push_back(&root);
		// construct Trie tree
		for (int k = 0; k < ps.size(); k++) {
			string p = ps[k];
			PMAnode * t = &root;
			for (int i = 0; i < p.size(); i++) {
				if (t->next[p[i]] == nullptr) { t->next[p[i]] = new PMAnode(id); id++; idto.push_back(t->next[p[i]]); }
				t = t->next[p[i]];
			}
			t->accept.push_back(k);
		}
		// construct failure link
		queue< PMAnode * > Q;
		for (char c = ' '; c <= '~'; c++) {
			if (root.next[c] != nullptr) {
				root.next[c]->fail = &root;
				Q.push(root.next[c]); // add node which is adjacent to root
			}
			else {
				root.next[c] = &root;
			}
		}
		while (!Q.empty()) {
			PMAnode *t = Q.front(); Q.pop();
			for (char c = ' '; c <= '~'; c++) {
				if (t->next[c] != nullptr) {
					Q.push(t->next[c]);
					PMAnode * r = t->fail;
					while (r->next[c] == nullptr) r = r->fail;
					t->next[c]->fail = r->next[c];
					vector<int> &tac = t->next[c]->accept;
					vector<int> &rac = r->next[c]->accept;
					tac.insert(tac.end(), rac.begin(), rac.end());
					sort(tac.begin(), tac.end());
					unique(tac.begin(), tac.end());
				}
			}
		}
	}
	// strを最後まで見たときの最終的なPMAnodeを返す
	PMAnode * match(string str) {
		PMAnode * t = &root;
		for (char c : str) {
			while (t->next[c] == nullptr) t = t->fail;
			t = t->next[c];
		}
		return t;
	}
	// strでマッチしたパターンの種類と回数を返す
	// res[i] := パターン文字列ps[i]のstrにおける出現回数
	vector< int > match_n(string str) {
		vector<int> res(n_pat, 0);
		PMAnode * t = &root;
		for (char c : str) {
			while (t->next[c] == nullptr) t = t->fail;
			t = t->next[c];
			for (int i = 0; i < t->accept.size(); i++) {
				res[t->accept[i]]++;
			}
		}
		return res;
	}
};

typedef ll Weight;
struct Edge {
	int src, dst;
	Weight weight;
	Edge(int src, int dst, Weight weight) :
		src(src), dst(dst), weight(weight) { }
};
bool operator < (const Edge &e, const Edge &f) {
	return e.weight != f.weight ? e.weight > f.weight : // !!INVERSE!!
	e.src != f.src ? e.src < f.src : e.dst < f.dst;
}
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

void shortestPath(const Graph &g, int s,
	vector<Weight> &dist, vector<int> &prev) {
	int n = g.size();
	dist.assign(n, INF); dist[s] = 0;
	prev.assign(n, -1);
	priority_queue<Edge> Q; // "e < f" <=> "e.weight > f.weight"
	for (Q.push(Edge(-2, s, 0)); !Q.empty(); ) {
		Edge e = Q.top(); Q.pop();
		if (prev[e.dst] != -1) continue;
		prev[e.dst] = e.src;
		for (auto f = g[e.dst].begin();f != g[e.dst].end();f++) {
			if (dist[f->dst] > e.weight + f->weight) {
				dist[f->dst] = e.weight + f->weight;
				Q.push(Edge(f->src, f->dst, e.weight + f->weight));
			}
		}
	}
}

vector<ll> dx{ -1, 0, 1, 0 };
vector<ll> dy{ 0, 1, 0, -1 };
vector<char> dc{ 'L', 'D', 'R', 'U' };

ll H, W;

ll f(ll id, ll y, ll x) {
	return (H + 2)*(W + 2)*id + (W + 2)*y + x;
}

int main() {
	while (cin >> H >> W, H != 0) {
		vector<string> area(H + 2, string(W + 2, '#'));
		for (int i = 1;i <= H;i++) {
			cin >> area[i];
			area[i] = "#" + area[i] + "#";
		}
		ll sy, sx, gy, gx;
		for (int y = 1;y <= H;y++)
			for (int x = 1;x <= W;x++)
				if (area[y][x] == 'S') {
					sx = x;
					sy = y;
				}
				else if (area[y][x] == 'G') {
					gy = y;
					gx = x;
				}
		ll P;
		cin >> P;
		vector<string> patt(P);
		for (int i = 0;i < P;i++)
			cin >> patt[i];
		PMA aho(patt);
		Graph g((H+2)*(W+2) * 100);
		for (int y = 1;y <= H;y++) {
			for (int x = 1;x <= W;x++) {
				if (area[y][x] == '#')
					continue;
				for (int node = 0;node < min(100, (int)aho.idto.size()); node++) {
					for (int k = 0;k < 4;k++) {
						ll nx = x + dx[k];
						ll ny = y + dy[k];
						if (area[ny][nx] == '#')
							continue;
						PMAnode* now = aho.idto[node];
						while (now->next[dc[k]] == nullptr) now = now->fail;
						now = now->next[dc[k]];
						if(now->accept.empty())
							g[f(node, y, x)].push_back(Edge(f(node, y, x), f(now->id, ny, nx), 1));
					}
				}
			}
		}
		vector<ll> dist;
		vector<int> prev;
		shortestPath(g, f(0, sy, sx), dist, prev);
		ll ans = INF;
		for (int i = 0;i < min(100, (int)aho.idto.size());i++)
			ans = min(ans, dist[f(i, gy, gx)]);
		if (ans == INF)
			cout << -1 << endl;
		else
			cout << ans << endl;
	}
	return 0;
}

Measured memory_bytes: 25892