您的位置:首页 > 其它

AC自动机专题

2014-05-26 18:10 423 查看
AC自动机简介:KMP是用于解决单模式串匹配问题, AC自动机用于解决多模式串匹配问题。

精华:设这个节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的节点。然后把当前节点的失败指针指向那个字目也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。

如果用KMP来解决多模式串匹配问题,则复杂度为O(n + k * m), 而AC自动机的负责度为O(n + m + z), z为模式串出现的次数。

学习链接:

http://hi.baidu.com/nialv7/item/ce1ce015d44a6ba7feded52d

http://blog.csdn.net/niushuai666/article/details/7002823

http://www.cnblogs.com/kuangbin/p/3164106.html

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222

思路:AC自动机的入门题,用的是bin牛的模板,统计End数组即可,统计过的需要清0.





1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 #define FOR(i, a, b) for (int i = (a); i < (b); ++i)
7 #define REP(i, a, b) for (int i = (a); i <= (b); ++i)
8 using namespace std;
9
10 const int MAX_N = (500000 + 500);
11 struct Trie {
12     int next[MAX_N][26], End[MAX_N], fail[MAX_N];
13     int root, L;
14     int NewNode()
15     {
16         FOR(i, 0, 26) next[L][i] = -1;
17         End[L++] = 0;
18         return L - 1;
19     }
20     void Init()
21     {
22         L = 0;
23         root = NewNode();
24     }
25     void Insert(char *str)
26     {
27         int len = strlen(str), now = root;
28         FOR(i, 0, len) {
29             int id = str[i] - 'a';
30             if (next[now][id] == -1) next[now][id] = NewNode();
31             now = next[now][id];
32         }
33         ++End[now];
34     }
35     void Build()
36     {
37         queue<int > que;
38         fail[root] = root;
39         FOR(i, 0, 26) {
40             if (next[root][i] == -1) next[root][i] = root;
41             else {
42                 fail[next[root][i]] = root;
43                 que.push(next[root][i]);
44             }
45         }
46         while (!que.empty()) {
47             int now = que.front();
48             que.pop();
49             FOR(i, 0, 26) {
50                 if (next[now][i] == -1) {
51                     next[now][i] = next[fail[now]][i];
52                 } else {
53                     fail[next[now][i]] = next[fail[now]][i];
54                     que.push(next[now][i]);
55                 }
56             }
57         }
58     }
59     int Query(char *str)
60     {
61         int len = strlen(str), now = root, res = 0;
62         FOR(i, 0, len) {
63             int id = str[i] - 'a';
64             now = next[now][id];
65             int tmp = now;
66             while (tmp != root) {
67                 res += End[tmp];
68                 End[tmp] = 0;
69                 tmp = fail[tmp];
70             }
71         }
72         return res;
73     }
74 } AC;
75
76 int n;
77 char str[1000000 + 100];
78
79 int main()
80 {
81     int Cas;
82     scanf("%d", &Cas);
83     while (Cas--) {
84         AC.Init();
85         scanf("%d", &n);
86         REP(i, 1, n) {
87             scanf("%s", str);
88             AC.Insert(str);
89         }
90         AC.Build();
91         scanf("%s", str);
92         printf("%d\n", AC.Query(str));
93     }
94     return 0;
95 }


View Code
 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896

思路:和上题差不多,只是用End数组来记录序号而已。





1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 #include <vector>
7 #define FOR(i, a, b) for (int i = (a); i < (b); ++i)
8 #define REP(i, a, b) for (int i = (a); i <= (b); ++i)
9 using namespace std;
10
11 const int MAX_N = (100000 + 1000);
12 struct Trie {
13
14     int next[MAX_N][128], End[MAX_N], fail[MAX_N];
15     int root, L;
16     int NewNode() {
17         FOR(i, 0, 128) next[L][i] = -1;
18         End[L++] = 0;
19         return L - 1;
20     }
21     void Init() {
22         L = 0;
23         root = NewNode();
24     }
25
26     void Insert(char *str, int index) {
27         int len = strlen(str), now = root;
28         FOR(i, 0, len) {
29             int id = str[i];
30             if (next[now][id] == -1) next[now][id] = NewNode();
31             now = next[now][id];
32         }
33         End[now] = index;
34     }
35     void Build() {
36         queue<int > que;
37         fail[root] = root;
38         FOR(i, 0, 128) {
39             if (next[root][i] == -1) next[root][i] = root;
40             else {
41                 fail[next[root][i]] = root;
42                 que.push(next[root][i]);
43             }
44         }
45         while (!que.empty()) {
46             int now = que.front();
47             que.pop();
48             FOR(i, 0, 128) {
49                 if (next[now][i] == -1) {
50                     next[now][i] = next[fail[now]][i];
51                 } else {
52                     fail[next[now][i]] = next[fail[now]][i];
53                     que.push(next[now][i]);
54                 }
55             }
56         }
57     }
58     void Query(char *str, vector<int > &ans) {
59         int len = strlen(str), now = root;
60         FOR(i, 0, len) {
61             now = next[now][str[i]];
62             int tmp = now;
63             while (tmp != root) {
64                 if (End[tmp]) ans.push_back(End[tmp]);
65                 tmp = fail[tmp];
66             }
67         }
68     }
69
70 } AC;
71
72 int N, M, res;
73 char str[10000 + 100];
74 vector<int > ans[1000 + 100];
75
76 int main()
77 {
78     AC.Init();
79     scanf("%d", &N);
80     REP(i, 1, N) {
81         scanf("%s", str);
82         AC.Insert(str, i);
83     }
84     AC.Build();
85     scanf("%d", &M);
86     FOR(i, 0, M) {
87         scanf("%s", str);
88         AC.Query(str, ans[i]);
89     }
90     res = 0;
91     FOR(i, 0, M) {
92         if ((int)ans[i].size()) {
93             printf("web %d:", i + 1);
94             sort(ans[i].begin(), ans[i].end());
95             FOR(j, 0, (int)ans[i].size()) printf(" %d", ans[i][j]);
96             puts("");
97             ++res;
98         }
99     }
100     printf("total: %d\n", res);
101     return 0;
102 }


View Code
 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3065

思路:用一个数组来记录模式串在主串中出现的次数。





1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 #define FOR(i, a, b) for (int i = (a); i < (b); ++i)
7 #define REP(i, a, b) for (int i = (a); i <= (b); ++i)
8 using namespace std;
9
10 const int MAX_N = (50000 + 500);
11
12 int N, num[1000 + 100];
13 char ss[1000 + 100][55];
14 char str[2000000 + 200];
15
16 struct Trie {
17     int next[MAX_N][128], End[MAX_N], fail[MAX_N];
18     int root, L;
19     int NewNode() {
20         FOR(i, 0, 128) next[L][i] = -1;
21         End[L++] = -1;
22         return L - 1;
23     }
24
25     void Init() {
26         L = 0;
27         root = NewNode();
28     }
29
30     void Insert(char *str, int index) {
31         int len = strlen(str), now = root;
32         FOR(i, 0, len) {
33             if (next[now][str[i]] == -1) next[now][str[i]] = NewNode();
34             now = next[now][str[i]];
35         }
36         End[now] = index;
37     }
38
39     void Build() {
40         queue<int > que;
41         fail[root] = root;
42         FOR(i, 0, 128) {
43             if (next[root][i] == -1) next[root][i] = root;
44             else {
45                 fail[next[root][i]] = root;
46                 que.push(next[root][i]);
47             }
48         }
49         while (!que.empty()) {
50             int now = que.front();
51             que.pop();
52             FOR(i, 0, 128) {
53                 if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
54                 else {
55                     fail[next[now][i]] = next[fail[now]][i];
56                     que.push(next[now][i]);
57                 }
58             }
59         }
60     }
61
62     void Query(char *str) {
63         memset(num, 0, sizeof(num));
64         int len = strlen(str), now = root;
65         FOR(i, 0, len) {
66             now = next[now][str[i]];
67             int tmp = now;
68             while (tmp != root) {
69                 if (End[tmp] != -1) ++num[End[tmp]];
70                 tmp = fail[tmp];
71             }
72         }
73         FOR(i, 0, N) {
74             if (num[i]) printf("%s: %d\n", ss[i], num[i]);
75         }
76     }
77
78 } AC;
79
80
81 int main()
82 {
83     while (~scanf("%d", &N)) {
84         AC.Init();
85         scanf("%d", &N);
86         FOR(i, 0, N) {
87             scanf("%s", ss[i]);
88             AC.Insert(ss[i], i);
89         }
90         AC.Build();
91         scanf("%s", str);
92         AC.Query(str);
93     }
94     return 0;
95 }


View Code
 

 题目链接:http://poj.org/problem?id=2778

思路:需要用到的知识:有向图中点A到点B走K步的路径数等于有向图原始矩阵的K次幂。然后对于已经建好的Trie图,我们就可以建图了,如果某个节点A不是终止节点并且这个节点的next节点B也不是终止节点,那么就连边(表示从A点走1步到节点B的方法有1种)。建好图之后就是矩阵的快速幂了,然后在统计节点0(根节点)到其余节点走N步的方法数的总和。





1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <algorithm>
5 #include <queue>
6 #define REP(i, a, b) for (int i = (a); i < (b); ++i)
7 #define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
8 using namespace std;
9
10 const int MAX_N = (100 + 10);
11 const int MOD = (100000);
12 int M, N;
13 char str[22];
14
15 struct Matrix {
16     long long mat[MAX_N][MAX_N];
17     int n;
18     Matrix() {}
19     Matrix(int _n)
20     {
21         n = _n;
22         REP(i, 0, n)
23         REP(j, 0, n) mat[i][j] = 0;
24     }
25     Matrix operator *(const Matrix &b) const
26     {
27         Matrix c = Matrix(n);
28         REP(i, 0, n) {
29             REP(j, 0, n) {
30                 REP(k, 0, n) {
31                     c.mat[i][j] += mat[i][k] * b.mat[k][j];
32                     if (c.mat[i][j] >= MOD) c.mat[i][j] %= MOD;
33                 }
34             }
35         }
36         return c;
37     }
38
39 };
40
41 Matrix Pow(Matrix mat, int n)
42 {
43     Matrix ONE = Matrix(mat.n);
44     REP(i, 0, mat.n) ONE.mat[i][i] = 1;
45     Matrix tmp = mat;
46     while (n) {
47         if (n & 1) ONE = ONE * tmp;
48         n >>= 1;
49         tmp = tmp * tmp;
50     }
51     return ONE;
52 }
53
54 struct Trie {
55     int next[MAX_N][4], End[MAX_N], fail[MAX_N];
56     int L, root;
57     int NewNode()
58     {
59         REP(i, 0, 4) next[L][i] = -1;
60         End[L++] = 0;
61         return L - 1;
62     }
63
64     void Init()
65     {
66         L = 0;
67         root = NewNode();
68     }
69
70     int getID(char ch)
71     {
72         if (ch == 'A') return 0;
73         if (ch == 'C') return 1;
74         if (ch == 'G') return 2;
75         if (ch == 'T') return 3;
76     }
77
78     void Insert(char *str)
79     {
80         int len = strlen(str), now = root;
81         REP(i, 0, len) {
82             int id = getID(str[i]);
83             if (next[now][id] == -1) next[now][id] = NewNode();
84             now = next[now][id];
85         }
86         End[now] = 1;
87     }
88
89     void Build()
90     {
91         queue<int > que;
92         fail[root] = root;
93         REP(i ,0, 4) {
94             if (next[root][i] == -1) next[root][i] = root;
95             else {
96                 fail[next[root][i]] = root;
97                 que.push(next[root][i]);
98             }
99         }
100         while (!que.empty()) {
101             int now =  que.front();
102             que.pop();
103             if (End[fail[now]]) End[now] = 1;
104             REP(i, 0, 4) {
105                 if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
106                 else {
107                     fail[next[now][i]] = next[fail[now]][i];
108                     que.push(next[now][i]);
109                 }
110             }
111         }
112     }
113
114     Matrix getMatrix()
115     {
116         Matrix res = Matrix(L);
117         REP(i, 0, L)
118         REP(j, 0, 4) if (!End[next[i][j]]) ++res.mat[i][next[i][j]];
119         return res;
120     }
121
122 } AC;
123
124
125 int main()
126 {
127     while (~scanf("%d %d", &M, &N)) {
128         AC.Init();
129         FOR(i, 1, M) scanf("%s", str), AC.Insert(str);
130         AC.Build();
131         Matrix tmp = AC.getMatrix();
132         tmp = Pow(tmp, N);
133         long long ans = 0;
134         REP(i, 0, tmp.n) {
135             ans += tmp.mat[0][i];
136             if (ans >= MOD) ans %= MOD;
137         }
138         printf("%lld\n", ans);
139     }
140     return 0;
141 }


 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=224

 思路:出现过给定单词的单词数 = 所有的单词数 -  没有出现过给定单词的单词数, 而所有的单词数 = 26^1 + 26^2 + ... + 26^L,没有出现过给定单词的单词数 = A + A^2 + ... + A^n,其中A是根据能走的字符之间的路径数建立的邻接矩阵。

那么如何求出A + A^2 + A^3 + ... + A^L?

可以这样做,依据等比矩阵的特点有:



于是可以很快计算出A^1+ A ^2 + ... + A ^L 以及 26^1 + 26^2 + ... + 26 ^ L的值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;

const int MAX_N = (33);
int N, L;
typedef unsigned long long ULL;

struct Matrix {
ULL mat[MAX_N][MAX_N];
int n;
Matrix(){}
Matrix(int _n) : n(_n) {
REP(i, 0, n)
REP(j, 0, n) mat[i][j] = 0;
}
};

Matrix Mul(const Matrix &a, const Matrix &b)
{
Matrix c = Matrix(a.n);
REP(i, 0, a.n) {
REP(j, 0, a.n)
REP(k, 0, a.n) c.mat[i][j] += a.mat[i][k] * b.mat[k][j];
}
return c;
}

Matrix Pow(Matrix p,int n)
{
Matrix ONE = Matrix(p.n);
REP(i, 0, ONE.n) ONE.mat[i][i] = 1;
while (n) {
if (n & 1) ONE = Mul(ONE, p);
n >>= 1;
p = Mul(p, p);
}
return ONE;
}

struct Trie {
int next[MAX_N][MAX_N], end[MAX_N], fail[MAX_N];
int root, L;
void Init() {
L = 0;
root = NewNode();
}

int NewNode() {
REP(i, 0, 26) next[L][i] = -1;
end[L++] = 0;
return (L - 1);
}

void Insert(char *str) {
int len = strlen(str), now = root;
REP(i, 0, len) {
int index = str[i] - 'a';
if (next[now][index] == -1)  next[now][index] = NewNode();
now = next[now][index];
}
end[now] = 1;
}

void Build() {
queue<int > que;
fail[root] = root;
REP(i, 0, 26) {
if (next[root][i] == -1) next[root][i]  = root;
else {
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while (!que.empty()) {
int now = que.front(); que.pop();
if (end[fail[now]]) end[now] = 1;
REP(i, 0, 26) {
if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}
Matrix getMatrix() {
Matrix tmp = Matrix(L + 1);
REP(i, 0, L) {
REP(j, 0, 26) if (!end[next[i][j]]) ++tmp.mat[i][next[i][j]];
}
REP(i, 0, L + 1) tmp.mat[i][L] = 1;
return tmp;
}
} AC;

int main()
{
while (cin >> N >> L) {
AC.Init();
FOR(i, 1, N) {
char str[MAX_N]; cin >> str;
AC.Insert(str);
}
AC.Build();
Matrix a = AC.getMatrix();
a = Pow(a, L);
ULL ans(0);
REP(i, 0, a.n) ans += a.mat[0][i];
ans -= 1;

a = Matrix(2);
a.mat[0][0] = 26, a.mat[0][1] = a.mat[1][1] = 1;
a = Pow(a, L);
ULL sum = a.mat[0][0] + a.mat[0][1];
sum -= 1;

cout << (sum - ans) << endl;
}
return 0;
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2825

思路:建立AC自动机,每个节点都代表一种状态,建立fail指针的时候顺便更新以该节点结尾的字符串代表的状态。

dp[i][j][k]代表最终密码长度为i,以AC自动机的位置j所在的字符结尾的,并且状态为k的密码的个数。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;

const int MAX_N = (10 * 10 + 10);
const int MOD = (20090717);
int N, M, K;
int num[1 << 11], dp[27][MAX_N][1 << 11]; //dp[i][j][k]表示长度为i,在AC自动机上的节点为L,并且状态为k的符合条件的个数

struct Trie {
int next[MAX_N][26], end[MAX_N], fail[MAX_N];
int root, L;
void Init() {
L = 0;
root = NewNode();
}

int NewNode() {
REP(i, 0, 26) next[L][i] = -1;
end[L++] = 0;
return (L - 1);
}

void Insert(char *str, int ID) {
int len = strlen(str), now = root;
REP(i, 0, len) {
int index = str[i] - 'a';
if (next[now][index] == -1) next[now][index] = NewNode();
now = next[now][index];
}
end[now] |= (1 << ID);
}

void Build() {
queue<int > que;
fail[root] = root;
REP(i, 0, 26) {
if (next[root][i] == -1) next[root][i] = root;
else {
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while (!que.empty()) {
int now = que.front(); que.pop();
end[now] |= end[fail[now]];
REP(i, 0, 26) {
if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}

int getDp() {
FOR(i, 0, N) {
REP(j, 0, L)
REP(s, 0, (1 << M)) dp[i][j][s] = 0;
}
dp[0][0][0] = 1;
REP(i, 0, N) {
REP(j, 0, L) {
REP(s, 0, (1 << M)) if (dp[i][j][s]) {
REP(k, 0, 26) {
dp[i + 1][next[j][k]][s | end[next[j][k]]] += dp[i][j][s];
if (dp[i + 1][next[j][k]][s | end[next[j][k]]] >= MOD) dp[i + 1][next[j][k]][s | end[next[j][k]]] %= MOD;
}
}
}
}
int ans = 0;
REP(s, 0, (1 << M)) if (num[s] >= K) {
REP(i, 0, L) {
ans += dp
[i][s];
if (ans >= MOD) ans %= MOD;
}
}
return ans;
}

} AC;

int main()
{
memset(num, 0, sizeof(num));
REP(s, 0, (1 << 12)) {
REP(i, 0, 12) if (s & (1 << i)) ++num[s];
}
while (cin >> N >> M >> K) {
if (N == 0 && M == 0 && K == 0) break;
AC.Init();
REP(i, 0, M) {
char str[11]; cin >> str;
AC.Insert(str, i);
}
AC.Build();
printf("%d\n",AC.getDp());

}
return 0;
}

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2296

思路:建立Trie,  end节点代表的该串的价值,dp[i][j]表示长度为i,在自动机上的位置为j的子串对应的价值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;

const int MAX_N = (1100 + 100);
int N, M, val[110];
int dp[55][MAX_N]; //dp[i][j] : 长度为i,以AC自动机上的位置j的字符为结尾的串的最大价值
string str[55][MAX_N];

bool cmp(const string &str1, const string &str2)
{
if ((int)str1.size() != (int)str2.size()) return (int)str1.size() < (int)str2.size();
return str1 < str2;
}

struct Trie {
int next[MAX_N][26], end[MAX_N], fail[MAX_N];
int root, L;

void Init() {
L = 0;
root = NewNode();
}

int NewNode() {
REP(i, 0, 26) next[L][i] = -1;
end[L++] = -1;
return (L - 1);
}

void Insert(char *str, int ID) {
int len = strlen(str), now = root;
REP(i, 0, len) {
int index = str[i] - 'a';
if (next[now][index] == -1) next[now][index] = NewNode();
now = next[now][index];
}
end[now] = ID;
}

void Build() {
queue<int > que;
fail[root] = root;
REP(i, 0, 26) {
if (next[root][i] == -1) next[root][i] = root;
else {
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while (!que.empty()) {
int now = que.front(); que.pop();
REP(i, 0, 26) {
if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}

void getAns() {
string ans("");
int maxval = 0, vv = 0;
memset(dp, -1, sizeof(dp));
dp[0][0] = 0;
str[0][0] = "";
REP(i, 0, N) {
REP(j, 0, L) if (dp[i][j] >= 0) {
REP(k, 0, 26) {
string tmp = str[i][j];
tmp += (char)('a' + k);
vv = dp[i][j];
if (end[next[j][k]] != -1) vv += val[end[next[j][k]]];
if (dp[i + 1][next[j][k]] < vv || (dp[i + 1][next[j][k]] == vv && cmp(tmp, str[i + 1][next[j][k]]))) {
dp[i + 1][next[j][k]] = vv;
str[i + 1][next[j][k]] = tmp;
if (vv > maxval || (vv == maxval && cmp(tmp, ans))) {
ans = tmp;
maxval = vv;
}
}
}
}
}
cout << ans << endl;
}

} AC;

int main()
{
int Cas;
cin >> Cas;
while (Cas--) {
cin >> N >> M;
AC.Init();
REP(i, 0, M) {
char str[20]; cin >> str;
AC.Insert(str, i);
}
REP(i, 0, M) cin >> val[i];
AC.Build();
AC.getAns();
}
return 0;
}


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2457

思路:dp[i][j]表示长度为i,在AC自动机上的位置为j满足条件的所需替换的字符的个数的最小值。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <queue>
#define REP(i, a, b) for (int i = (a); i < (b); ++i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;

const int MAX_N = (1000 + 10);
template < typename T > inline T getMIN(const T &a, const T &b)
{
return a < b ? a : b;
}
int N, dp[MAX_N][MAX_N]; //len, pos;
char str[MAX_N];

struct Trie {
int next[MAX_N][4], end[MAX_N], fail[MAX_N];
int L, root;

void Init() {
L = 0;
root = NewNode();
}

int NewNode() {
REP(i, 0, 4) next[L][i] = -1;
end[L++] = 0;
return (L - 1);
}

int getchange(char ch) {
if (ch == 'A') return 0;
if (ch == 'C') return 1;
if (ch == 'G') return 2;
if (ch == 'T') return 3;
return -1;
}

void Insert(char *str) {
int len = strlen(str), now = root;
REP(i, 0, len) {
int id = getchange(str[i]);
if (next[now][id] == -1) next[now][id] = NewNode();
now = next[now][id];
}
end[now] = 1;
}

void Build() {
queue<int > que;
fail[root] = root;
REP(i, 0, 4) {
if (next[root][i] == -1) next[root][i] = root;
else {
fail[next[root][i]] = root;
que.push(next[root][i]);
}
}
while (!que.empty()) {
int now = que.front(); que.pop();
if (end[fail[now]]) end[now] = 1;
REP(i, 0, 4) {
if (next[now][i] == -1) next[now][i] = next[fail[now]][i];
else {
fail[next[now][i]] = next[fail[now]][i];
que.push(next[now][i]);
}
}
}
}

int getDp(char *str) {
memset(dp, 0x3f, sizeof(dp));
int len = strlen(str);
dp[0][0] = 0;
REP(i, 0, len) {
REP(j, 0, L) if (!end[j] && dp[i][j] < 0x3f3f3f3f){
REP(k, 0, 4) if (!end[next[j][k]]) {
int val = (k != getchange(str[i]));
dp[i + 1][next[j][k]] = getMIN(dp[i + 1][next[j][k]], dp[i][j] + val);
}
}
}
int ans = 0x3f3f3f3f;
REP(i, 0, L) ans = getMIN(ans, dp[len][i]);
if (ans == 0x3f3f3f3f) return -1;
return ans;
}
} AC;

int main()
{
int t = 1;
while (cin >> N && N) {
AC.Init();
REP(i, 0, N) {
char ss[22]; cin >> ss;
AC.Insert(ss);
}
cin >> str;
AC.Build();
printf("Case %d: %d\n", t++, AC.getDp(str));
}
return 0;
}

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: