先对所有的串建立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; }