Trie图
AC自动机是KMP的多串形式,当文本串失配时,AC自动机的fail指针告诉我们应该跳到哪里去继续匹配(跳到当前匹配串的最长后缀去),所以AC自动机的状态是有限的
但是AC自动机具有不确定性, 比如要求x结点的孩子c的fail指针(x->next[c]->fail), 如果x的fail指针指向的结点没有c孩子(x-fail->next[c]==NULL),
那么就要去看x的fail指针指向的结点的的fail指针指向的结点有没有孩子c(x->fail->fail->next[c] 是否为NULL),一直这样子迭代, 知道fail指针指向根结点为止
这样子的原因在于next指针的指向可能为空, Trie图就是补全了这些next指针的AC自动机,所以Trie图是确定性的有限状态自动机
那么如果补全这些next指针呢?
首先让第二层为空的next指针(第一层是根结点)都指向root,这是成里的, 如果匹配的时候如果第一个字符就不匹配, 那么肯定是回到root重新匹配
然后让下一层为空的next[i]指针指向上一层fail指针指向的next[i]指针(即也是指向自己的最长后缀)
Trie图的fail指针的求法与AC自动机一样, 这样子就能构件出Trie图了
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <algorithm> 5 #include <iostream> 6 #include <queue> 7 #include <stack> 8 #include <vector> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <math.h> 13 using namespace std; 14 #pragma warning(disable:4996) 15 typedef unsigned __int64 LL; 16 const int INF = 1<<30; 17 /* 18 */ 19 const int N = 40; 20 struct Node 21 { 22 int fail, next[26]; 23 bool isWord; 24 void init() 25 { 26 fail = -1; 27 isWord = false; 28 for (int i = 0; i < 26; ++i) 29 next[i] = -1; 30 } 31 }Trie[N]; 32 int size; 33 void insert(int root, char *str) 34 { 35 int idx, cur = root; 36 for (int i = 0; str[i]; ++i) 37 { 38 idx = str[i] - 'a'; 39 if (Trie[cur].next[idx] == -1) 40 { 41 Trie[size].init(); 42 Trie[cur].next[idx] = size++; 43 } 44 cur = Trie[cur].next[idx]; 45 } 46 Trie[cur].isWord = true; 47 } 48 void makeFail(int root) 49 { 50 queue<int> q; 51 for (int i = 0; i < 26; ++i) 52 { 53 if (Trie[root].next[i] == -1) 54 Trie[root].next[i] = root; 55 else 56 { 57 Trie[Trie[root].next[i]].fail = root; 58 q.push(Trie[root].next[i]); 59 } 60 } 61 while (!q.empty()) 62 { 63 int cur = q.front(); 64 q.pop(); 65 for (int i = 0; i < 26; ++i) 66 { 67 if (Trie[Trie[cur].fail].isWord) 68 Trie[cur].isWord = true; 69 if (Trie[cur].next[i] == -1) 70 Trie[cur].next[i] = Trie[Trie[cur].fail].next[i]; 71 else 72 { 73 Trie[Trie[cur].next[i]].fail = Trie[Trie[cur].fail].next[i]; 74 q.push(Trie[cur].next[i]); 75 } 76 } 77 } 78 } 79 80 int main() 81 { 82 int n, L; 83 char word[10]; 84 while (scanf("%d", &n,) != EOF) 85 { 86 Trie[0].init(); 87 Trie[0].fail = 0; 88 size = 1; 89 for (int i = 0; i < n; ++i) 90 { 91 scanf("%s", word); 92 insert(0, word); 93 } 94 makeFail(0); 95 96 97 } 98 return 0; 99 }