先对所有的串建立AC自动机,令dp[i][j][k]代表在AC自动机上走了i步,达到j行,k列所需要的最小步数,然后转移用spfa转移就可以了。。。。
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 20025
#define maxm 4005
#define eps 1e-7
#define mod 1000000007
#define INF 0x3f3f3f3f
#define PI (acos(-1.0))
#define lowbit(x) (x&(-x))
#define mp make_pair
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid
#define rson o<<1 | 1, mid+1, R
#define pii pair<int, int>
#pragma comment(linker, "/STACK:16777216")
typedef long long LL;
typedef unsigned long long ULL;
//typedef int LL;
using namespace std;
LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}
LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}
// head
struct AC
{
int next[maxn][26];
int fail[maxn];
bool end[maxn];
char s[maxn];
queue<int> q;
int root, tail, now;
int newnode()
{
end[tail] = 0;
fail[tail] = -1;
memset(next[tail], -1, sizeof next[tail]);
return tail++;
}
void init()
{
tail = 0;
root = newnode();
}
void insert()
{
scanf("%s", s);
int len = strlen(s);
now = root;
for(int i = 0; i < len; i++) {
int t = s[i] - 'A';
if(next[now][t] == -1) next[now][t] = newnode();
now = next[now][t];
}
end[now] = true;
}
void build()
{
now = root;
for(int i = 0; i < 26; i++)
if(next[now][i] == -1) next[now][i] = root;
else {
fail[next[now][i]] = root;
q.push(next[now][i]);
}
while(!q.empty()) {
now = q.front();
q.pop();
end[now] |= end[fail[now]];
for(int i = 0; i < 26; i++)
if(next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
q.push(next[now][i]);
}
}
}
};
struct node
{
int si, sj, sk;
node() {}
node(int si, int sj, int sk) : si(si), sj(sj), sk(sk) {}
};
AC ac;
queue<node> q;
int dp[maxn][22][22];
bool in[maxn][22][22];
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char g[55][55];
int n, m, ans;
void spfa()
{
while(!q.empty()) {
int x = q.front().sj, y = q.front().sk, t = q.front().si;
in[t][x][y] = false;
q.pop();
for(int i = 0; i < 4; i++) {
int xx = x + dir[i][0], yy = y + dir[i][1];
if(xx < 0 || yy < 0 || xx >= n || yy >= m) continue;
if(g[xx][yy] == '#') continue;
if(g[xx][yy] == '.') {
if(dp[t][xx][yy] > dp[t][x][y] + 1) {
dp[t][xx][yy] = dp[t][x][y] + 1;
if(!in[t][xx][yy]) in[t][xx][yy] = true, q.push(node(t, xx, yy));
}
}
else {
int tt = g[xx][yy] - 'A';
tt = ac.next[t][tt];
if(dp[tt][xx][yy] > dp[t][x][y] + 1) {
dp[tt][xx][yy] = dp[t][x][y] + 1;
if(!in[tt][xx][yy]) in[tt][xx][yy] = true, q.push(node(tt, xx, yy));
}
}
}
if(g[x][y] != '.') {
int tt = g[x][y] - 'A';
tt = ac.next[t][tt];
if(dp[tt][x][y] > dp[t][x][y]) {
dp[tt][x][y] = dp[t][x][y];
if(!in[tt][x][y]) in[tt][x][y] = true, q.push(node(tt, x, y));
}
}
}
}
void read()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) scanf("%s", g[i]);
int k;
scanf("%d", &k);
ac.init();
for(int i = 0; i < k; i++) ac.insert();
ac.build();
}
void work()
{
memset(dp, INF, sizeof dp);
memset(in, 0, sizeof in);
int si = 0, sj = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(g[i][j] == '@') si = i, sj = j, g[i][j] = '.';
dp[0][si][sj] = 0;
in[0][si][sj] = true;
q.push(node(0, si, sj));
ans = INF;
spfa();
for(int i = 1; i < ac.tail; i++)
if(ac.end[i])
for(int j = 0; j < n; j++)
for(int k = 0; k < m; k++)
ans = min(ans, dp[i][j][k]);
printf("%d\n", ans == INF ? -1 : ans);
}
int main()
{
int _;
scanf("%d", &_);
while(_--) {
read();
work();
}
return 0;
}