Aho_Corasick自动机(AC自动机)
首先,AC自动机不是Accept自动机,别以为把这段代码复制到OJ上就全都自动AC了……
其实这玩意是Aho-Corasick 造出来的,所以你懂的。
那么这玩意能干嘛咧?
•字符串的匹配问题
•多串的匹配问题※
看不懂吧?解释一下:
例如给几个单词 acbs,asf,dsef,再给出一个 很长的文章,acbsdfgeasf,问在这个文章中,总共出现了多少个单词,或者是单词出现的总次数。
怎么实现的呢,就是KMP+trie树。是以KMP为算法基础,trie为索引结构的东东。那它如何与kmp联系在一起?
•关键是在trie树上加了一种fail指针。
•Fail指针的用途:就像是kmp中的next的数组。
在字符串失配的时候确定转移的节点。AC难点就是指针的算法,看下面这么多图:模板:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #include <queue> 7 #define REP(i, s, n) for(int i = s; i <= n; i ++) 8 #define RAP(i, n, s) for(int i = n; i >= s; i --) 9 #define now ch[x][c] 10 using namespace std; 11 const int maxn = 400000 + 10; 12 const int maxsig = 2; 13 char S[10000 + 10]; 14 int n; 15 inline void read(int &x){ 16 x = 0; int sig = 1; char ch = getchar(); 17 while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); } 18 while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar(); 19 x *= sig; return ; 20 } 21 inline void write(int x){ 22 if(x == 0) { putchar('0'); return; } 23 if(x < 0) putchar('-'), x = -x; 24 int len = 0, buf[20]; 25 while(x) buf[len ++] = x % 10, x /= 10; 26 RAP(i, len - 1, 0) putchar(buf[i] + '0'); return ; 27 } 28 namespace Aho_Corasick{ 29 int ch[maxn][maxsig], val[maxn], f[maxn], last[maxn], len[maxn], ms; 30 void AC_init(){ 31 ms = 0; 32 memset(ch, 0, sizeof(ch)); 33 memset(val, 0, sizeof(val)); 34 memset(f, 0, sizeof(f)); 35 memset(last, 0, sizeof(last)); 36 memset(len, 0, sizeof(len)); 37 return ; 38 } 39 void insert(char* s, int v){ 40 int x = 0, i; 41 for(i = 0; s[i] != '\0'; i ++){ 42 int c = s[i] - '0'; if(!now) now = ++ ms; x = now; 43 } 44 val[x] = v; len[x] = i; return ; 45 } 46 void getfail(){ 47 queue<int> Q; 48 REP(i, 0, maxsig - 1) if(ch[0][i]) Q.push(ch[0][i]); 49 while(!Q.empty()){ 50 int x = Q.front(); Q.pop(); 51 REP(c, 0, maxsig - 1){ 52 if(!now) { now = ch[f[x]][c]; continue; } 53 Q.push(now); int cur = f[x]; 54 while(cur && !now) cur = f[cur]; 55 f[now] = ch[cur][c]; last[now] = val[f[now]] ? f[now] : last[f[now]]; 56 } 57 } 58 return ; 59 } 60 void AC_print(int i, int j){ 61 if(j){ 62 write(val[j]); printf(": "); 63 write(i - len[j] + 1); printf(" to "); 64 write(i); putchar('\n'); 65 AC_print(i, last[j]); 66 } 67 return ; 68 } 69 void solve(char* T){ 70 int cur = 0; 71 for(int i = 0; T[i] != '\0'; i ++){ 72 cur = ch[cur][T[i] - '0']; 73 if(val[cur]) AC_print(i, cur); 74 else if(last[cur]) AC_print(i, last[cur]); 75 } 76 return ; 77 } 78 }using namespace Aho_Corasick; 79 bool init(){ 80 read(n); if(!n) return false; 81 AC_init(); 82 REP(i, 1, n) scanf("%s", S), insert(S, i); 83 return true; 84 } 85 void work(int cur){ 86 getfail(); 87 scanf("%s", S); 88 printf("Case "); write(cur); 89 printf(":\n"); 90 solve(S); 91 return ; 92 } 93 void print(){ 94 95 return ; 96 } 97 int main(){ 98 int Case = 1; 99 while(init()) work(Case ++); 100 return 0; 101 }