AC自动机+DP。。。dp[i][j]表示在AC自动机上走i步,到达AC自动机上节点j,所需要的最小步数。刚开始dp数组全部初始化为无穷大,dp[0][0]初始化为0。每走一步,如果到达的点不是病毒串的节点,那么就直接转移下去,如果是病毒串的节点,那么就找其他3个节点,如果有不是病毒串的节点,就转移下去并加上1。然后就酱紫喽。。
#include <iostream> #include <sstream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <bitset> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <climits> #define maxn 1005 #define eps 1e-6 #define mod 10007 #define INF 99999999 #define lowbit(x) ((x)&(-(x))) #define lson o<<1, L, mid #define rson o<<1 | 1, mid+1, R typedef long long LL; using namespace std; struct trie { int next[maxn][4]; int fail[maxn]; int end[maxn]; char s[maxn]; int hash[maxn]; queue<int> q; int top, root, now; int newnode(void) { fail[top] = -1; end[top] = 0; for(int i = 0; i < 4; i++) next[top][i] = -1; return top++; } void init(void) { top = 0; root = newnode(); memset(hash, -1, sizeof hash); hash['A' - 'A'] = 0; hash['C' - 'A'] = 1; hash['G' - 'A'] = 2; hash['T' - 'A'] = 3; } void insert(void) { int i, k, len = strlen(s); now = root; for(i = 0; i < len; i++) { k = hash[s[i] - 'A']; if(next[now][k] == -1) next[now][k] = newnode(); now = next[now][k]; } end[now] = 1; } void build(void) { now = root; for(int i = 0; i < 4; 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(); if(end[fail[now]]) end[now] = 1; for(int i = 0; i < 4; 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]); } } } }tmp; int dp[maxn][maxn]; char s[maxn]; int n; void init(void) { memset(dp, 0, sizeof dp); } void read(void) { tmp.init(); for(int i = 0; i < n; i++) { scanf("%s", tmp.s); tmp.insert(); } tmp.build(); scanf("%s", s); } void work(void) { int i, j, k, kk, ans; int len = strlen(s); for(i = 0; i <= len; i++) for(j = 0; j < tmp.top; j++) dp[i][j] = INF; dp[0][0] = 0; for(i = 0; i < len; i++){ kk = tmp.hash[s[i] - 'A']; for(j = 0; j < tmp.top; j++) { if(dp[i][j] != INF) { if(tmp.end[tmp.next[j][kk]] == 0) dp[i+1][tmp.next[j][kk]] = min(dp[i+1][tmp.next[j][kk]], dp[i][j]); for(k = 0; k < 4; k++) if(tmp.end[tmp.next[j][k]] == 0) dp[i+1][tmp.next[j][k]] = min(dp[i+1][tmp.next[j][k]], dp[i][j] + 1); } } } ans = INF; for(i = 0; i < tmp.top; i++) ans = min(ans, dp[len][i]); if(ans == INF) printf("-1\n"); else printf("%d\n", ans); } int main(void) { int _ = 0; while(scanf("%d", &n), n!=0) { read(); printf("Case %d: ", ++_); work(); } return 0; }