ac自动机说起来很复杂,其实和kmp是一样的思路,都是寻找相同前后缀,减少跳的次数。只要理解了kmp是怎么求next数组的,ac自动机bfs甚至比knp还好写。
这里大致说一下kmp求next数组的方法吧,假设现在要求第c个字符的next值(假设这个c很大,这样画图出来比较清晰方便理解),因为遍历过程中我们已经知道了第c-1个字符的next为x(假设比c小很多),即next[c-1] = x。那就代表我们知道了a[1]—a[x]这一段和a[c-1-x]—a[c-1]这一段是相等的对吧。
那么现在有两种情况
一。a[x+1] 和 a[c]相等,那么显然变成了a[1]—a[x+1] 这一段和a[c-1-x]—a[c]这一段相等,即c位置的相同前后缀长度比c-1多了1,就是next[c-1]+1;
即原来是:
1——————————x == c-1-x ————————————————c-1 ① 由于a[x+1] == a[c],变成了
1——————————x+1 == c-1-x——————————————————c
二。如果不相等,那么我们在1——x这一段下功夫,假设next[x] = y,即1——y == x-y——x这两段相等,注意根据①式,x-y——x == c-1-y——c-1,画个图就很清楚了,所以如果a[y+1] == a[c],那么相同前后缀长度就是y+1了。
即因为
1——————————x == c-1-x————————————————c-1
1——y == x-y———x == c-1-x——c-1-x+y == c-1-y————c-1 由于a[y+1] == a[c],变成了
1——y+1 == c-1-y——————c
那如果a[y+1] 与a[c]还是不相等怎么办?其实细心的话应该发现这是一个递归过程了——只要再找next[y],循环上面的过程就可以了,想明白这个过程再去看求next数组的代码就很容易理解了。
最后还是上这道题代码:
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <queue> 5 #include <set> 6 #include <stack> 7 #include <math.h> 8 #include <string> 9 #include <algorithm> 10 11 #define SIGMA_SIZE 26 12 #define pii pair<int,int> 13 #define lson rt<<1 14 #define rson rt<<1|1 15 #define lowbit(x) (x&-x) 16 #define fode(i, a, b) for(int i=a; i>=b; i--) 17 #define foe(i, a, b) for(int i=a; i<=b; i++) 18 #define fod(i, a, b) for(int i=a; i>b; i--) 19 #define fo(i, a, b) for(int i=a; i<b; i++) 20 //#pragma warning ( disable : 4996 ) 21 22 using namespace std; 23 typedef long long LL; 24 inline LL LMax(LL a, LL b) { return a>b ? a : b; } 25 inline LL LMin(LL a, LL b) { return a>b ? b : a; } 26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); } 27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm 28 inline int Max(int a, int b) { return a>b ? a : b; } 29 inline int Min(int a, int b) { return a>b ? b : a; } 30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } 31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm 32 const LL INF = 0x3f3f3f3f3f3f3f3f; 33 const LL lmod = 1e9+7; 34 const int mod = 10000; 35 const double eps = 1e-8; 36 const int inf = 0x3f3f3f3f; 37 const int maxk = 1e5+5; 38 const int maxm = 510*510; 39 const int maxn = 5e5+10; 40 41 struct node { 42 node *fail, *s[26]; 43 int w; 44 node() {} 45 46 void init() { 47 fail = NULL; 48 fo(i, 0, 26) s[i] = NULL; 49 w = 0; 50 } 51 }*head; 52 53 54 int n, ans; 55 char str[1000010]; 56 queue<node*> q; 57 58 node* getfail(node* p, int x) 59 { 60 if (p->s[x] != NULL) return p->s[x]; 61 else { 62 if (p == head) return head; 63 else return getfail(p->fail, x); 64 } 65 } 66 67 void build() 68 { 69 node* root = head; 70 node* tmp; 71 72 int len = strlen(str); 73 for ( int j = 0; j < len; j++ ) 74 { 75 int k = str[j]-‘a‘; 76 if (root->s[k] == NULL) { 77 tmp = new node; tmp->init(); 78 tmp->fail = head; 79 root->s[k] = tmp; 80 } 81 82 root = root->s[k]; 83 //标记单词结尾 84 if (j == len-1) root->w++; 85 } 86 } 87 88 void build_ac() 89 { 90 node* r; 91 while(!q.empty()) q.pop(); 92 q.push(head); 93 while(!q.empty()) 94 { 95 r = q.front(); q.pop(); 96 fo(j, 0, 26) 97 { 98 if (r->s[j] != NULL) { 99 q.push(r->s[j]); 100 if (r == head) r->s[j]->fail = head; 101 else r->s[j]->fail = getfail(r->fail, j); 102 } 103 } 104 } 105 return; 106 } 107 108 void solve() 109 { 110 int len = strlen(str); 111 node *tmp, *r = head; 112 fo(j, 0, len) 113 { 114 int k = str[j]-‘a‘; 115 //找到前缀 116 while( r->s[k]==NULL && r != head ) r = r->fail; 117 //自动机向下匹配 118 //如果可以匹配,则进入下一节点,否则返回头节点 119 r = (r->s[k]==NULL) ? head : r->s[k]; 120 tmp = r; 121 122 //如果单词a出现,则他的前缀也全部出现过 123 while(tmp != head) { 124 ans += tmp->w; 125 tmp->w = 0; 126 tmp = tmp->fail; 127 } 128 } 129 return; 130 } 131 132 133 134 void init() 135 { 136 cin >> n; ans = 0; 137 head = new node, head->init(); 138 foe(i, 1, n) 139 scanf("%s", str), build(); 140 141 build_ac(); 142 scanf("%s", str); 143 } 144 145 int main() 146 { 147 148 #ifndef ONLINE_JUDGE 149 freopen("input.txt", "r", stdin); 150 #endif 151 152 int t; cin >> t; 153 while(t--) 154 { 155 init(); 156 solve(); 157 printf("%d\n", ans); 158 } 159 160 return 0; 161 }
原文地址:https://www.cnblogs.com/chaoswr/p/9783281.html