1. 程式人生 > >2018/2/22 每日一學 AC自動機

2018/2/22 每日一學 AC自動機

指針 math pan make () clas ring query mat

AC自動機=trie樹+KMP。

代碼如下:(自行理解)

#include<cstdio>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#define N 500006
using namespace std;

char st[1000005];
char keyword[55];
int n,m;
int next[N][26],cnt[N],fail[N],pos;

int newnode()
{
    for(int i=0; i<26
; i++) next[pos][i] = 0; fail[pos] = cnt[pos] = 0; return pos++; } void insert(char *s) //構造trie { int i,p = 0; for(i=0; s[i]; i++) { int k = s[i] - a, &x = next[p][k]; p = x?x : x = newnode(); } cnt[p]++; // 位運算要用 } void makenext() // 構造失敗指針 { int i; queue
<int>q; q.push(0); while(!q.empty()) // 這個代碼為什麽會這麽強? { int u = q.front(); cnt[u] += cnt[fail[u]]; q.pop(); for(i=0; i<26; i++) { int v = next[u][i]; if(v == 0) next[u][i] = next[fail[u]][i]; // why? 缺少v, 求next
else q.push(v); if(u && v) { fail[v]=next[fail[u]][i]; // 為什麽只弄了一下? 如果沒有會怎麽樣? 求fail } } } } int query(char *s) { int ret = 0, idx, d = 0; for(int i=0; s[i]; i++) { idx = s[i] - a; d = next[d][idx]; ret += cnt[d]; cnt[d] = 0; } return ret; } int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d",&n); pos = 0, newnode(); for(int i=0; i<n; i++) { scanf("%s",keyword); insert(keyword); } makenext(); scanf(" %s",st); printf("%d\n",query(st)); } }

2018/2/22 每日一學 AC自動機