学习AC自动机请戳这里:大神blog........
自动机的模板:
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include <set> #include <queue> #include <stack> #include <climits>//形如INT_MAX一类的 #define MAX 100005 #define INF 0x7FFFFFFF #define REP(i,s,t) for(int i=(s);i<=(t);++i) #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define L(x) x<<1 #define R(x) x<<1|1 # define eps 1e-5 //#pragma comment(linker, "/STACK:36777216") ///传说中的外挂 using namespace std; struct trie { trie *fail; //失败指针 trie *next[26]; int cnt; trie () { fail = 0;cnt = 0; memset(next,0,sizeof(next)); } }*q[511111]; //模拟队列 trie *rt; int head,tail; char keyword[51]; char book[1111111]; void insert(char *key) { trie *p = rt; int t; while(*key) { t = *key - 'a'; if(p->next[t] == NULL) p->next[t] = new trie(); p = p->next[t]; key++; } p->cnt++; //表示一个单词 } void bfs() { rt->fail = NULL; //根结点fail指向空 q[head++] = rt; while(head != tail) { trie *t = q[tail++]; trie *p = NULL; for(int i=0; i<26; i++) { if(t->next[i] != NULL) { //对所有儿子的fail指针匹配并且入队 if(t == rt) t ->next[i]->fail = rt; //如果刚从根节点出发 else { //否则沿着他父亲的失败指针走, //直到走到一个节点,他的儿子中也有相同字符的节点。然后把当前节点的失败指针指向他的那个儿子 p = t->fail; while(p != NULL) { if(p->next[i] != NULL) { t->next[i]->fail = p->next[i]; break; } p = p->fail; } if(p == NULL) t->next[i]->fail = rt; //如果一直走到了root都没找到,那就把失败指针指向root } q[head++] = t->next[i]; } } } } int query(char *key) { trie *p = rt; int cnt = 0; while(*key) { int t = *key - 'a'; while(p->next[t] == NULL && p != rt) p = p->fail; //如果当前字符不匹配 p = p->next[t]; if(p == NULL) p = rt; //最终还是未匹配 trie *tmp = p; while(tmp != rt && tmp->cnt != -1) { cnt += tmp->cnt; tmp->cnt = -1; //该处已经出现过了 tmp = tmp->fail; } key++; } return cnt; } int main(){ int T; cin >> T; while(T --) { rt = new trie(); int n; cin >> n; for(int i=0; i<n; i++) { scanf("%s",keyword); insert(keyword); } head = 0; tail = 0; bfs(); scanf("%s",book); printf("%d\n",query(book)); } return 0; }
来一发静态数组实现的,毕竟数组型的才能和其他算法结合使用~~~
#include <iostream> #include <algorithm> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include <set> #include <queue> #include <stack> #include <climits>//形如INT_MAX一类的 #define MAX 100005 #define INF 0x7FFFFFFF #define REP(i,s,t) for(int i=(s);i<=(t);++i) #define LL long long #define mem(a,b) memset(a,b,sizeof(a)) #define mp(a,b) make_pair(a,b) #define L(x) x << 1 #define R(x) x << 1 | 1 # define eps 1e-5 //#pragma comment(linker, "/STACK:36777216") ///传说中的外挂 using namespace std; struct AC_AUTO { int next[26] ; int fail ; int num ; void init() { memset(next,0,sizeof(next)) ; fail = -1 ; num = 0 ; } } a[500000]; int cnt; char keyword[55]; char str[1111111]; void insert(char *s) { int p = 0 ; for(int i = 0 ; s[i] ; i ++) { int t = s[i] - 'a' ; if(a[p].next[t] == 0) { a[cnt].init(); a[p].next[t] = cnt ++; } p = a[p].next[t] ; } a[p].num ++; } int q[511111] ; void ac_bfs() { int i,head = 0,tail = 0; q[tail ++] = 0; while(head < tail) { int front = q[head ++]; for(i = 0; i < 26 ; i ++) { if(a[front].next[i] != 0) { int p = a[front].fail ; while(p != -1) { if(a[p].next[i] != 0) { a[a[front].next[i]].fail = a[p].next[i] ; break ; } p = a[p].fail ; } if(p == -1) a[a[front].next[i]].fail = 0 ; q[tail ++] = a[front].next[i] ; } } } } int query() { int sum = 0,len = strlen(str); int p = 0 ; for(int i=0; i<len; i++) { int t = str[i] - 'a' ; while(a[p].next[t] == 0 && p != 0) p = a[p].fail ; p = a[p].next[t] ; int tmp = p; while(tmp != 0 && a[tmp].num != -1) { sum += a[tmp].num ; a[tmp].num = -1 ; tmp = a[tmp].fail ; } } return sum; } int main() { int T,n; scanf("%d",&T); while(T --) { a[0].init(); cnt = 1; //注意 scanf("%d",&n); for(int i=0; i<n; i++) { scanf("%s",keyword); insert(keyword); } ac_bfs(); scanf("%s",str); printf("%d\n",query()); } return 0; }