基本照抄cxlove代码。。。AC自动机+DP。表示终于比较明白自动机了。之前真的不是很清晰。
DP是二维,一维是字符串序号,一维是字典树中状态。下一点不是单词结束点即可转移过去。
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define N 2000005
#define INF 1000000009
typedef long long LL;
struct Trie {
Trie *fail;
Trie *next[4];
int isword;
int kind;
};
Trie s[N];
Trie *que[N];
int ptr = 0;
int change(char xxx){
if(xxx == 'A')return 0;
if(xxx == 'G')return 1;
if(xxx == 'C')return 2;
return 3;
}
Trie *NewNode(){
Trie *p = &s[ptr];
for(int i = 0; i < 4; i++)p->next[i] = NULL;
p->fail = NULL;
p->isword = 0;
p->kind = ptr++;
return p;
}
void Insert(char *c, Trie *root){
int len = strlen(c);
Trie *p = root;
for(int i = 0; i < len; i++){
if(p->next[change(c[i])] == NULL)p->next[change(c[i])] = NewNode();
p = p->next[change(c[i])];
}
p->isword = 1;
}
void Build_fail(Trie *root){
Trie *tmp = root;
root->fail = NULL;
int head = 0, tail = 0;
que[tail++] = tmp;
while(head < tail){
tmp = que[head++];
for(int i = 0; i < 4; i++){
if(tmp->next[i]){
if(tmp == root)tmp->next[i]->fail = root;
else {
Trie *p = tmp->fail;
while(p != NULL){
if(p->next[i]){
tmp->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if(p == NULL)tmp->next[i]->fail = root;
}
if(tmp->next[i]->fail->isword)tmp->next[i]->isword = 1;
que[tail++] = tmp->next[i];
}
else if(tmp == root)tmp->next[i] = root;
else tmp->next[i] = tmp->fail->next[i];
}
}
}
int dp[1005][2005];
char str[1005];
char sub[1005];
int n;
int solve(){
int len = strlen(str);
for(int i = 0; i <= len; i++)
for(int j = 0; j < ptr; j++)
dp[i][j] = INF;
dp[0][0] = 0;
for(int i = 1; i <= len; i++){
for(int j = 0; j < ptr; j++){
if(dp[i - 1][j] == INF)continue;
if(s[j].isword)continue;
for(int k = 0; k < 4; k++){
int r = s[j].next[k]->kind;
if(s[r].isword)continue;
dp[i][r] = min(dp[i][r], dp[i - 1][j] + (change(str[i - 1]) != k));
}
}
}
int ans = INF;
for(int i = 0; i < ptr; i++){
if(dp[len][i] < ans)ans = dp[len][i];
}
return ans == INF ? -1 : ans;
}
int main(){
int cas = 1;
while(scanf("%d", &n) && n){
ptr = 0;
Trie *root = NewNode();
for(int i = 0; i < n; i++){
scanf("%s", sub);
Insert(sub, root);
}
Build_fail(root);
scanf("%s", str);
printf("Case %d: ", cas++);
printf("%d\n", solve());
}
return 0;
}