AC自动机入门题目(HDU

来源:互联网 发布:淘宝电脑详情页尺寸 编辑:程序博客网 时间:2024/05/21 04:43

AC自动机其实就是 字典树+KMP。 最开始的时候我没有刷字典树的题目,所以不是很能理解, 但是刷完字典树之后,对AC自动机得理解就比较简单了。
AC自动机的构造中有3个需要注意的地方:
1、next[i][j] 这个next里面存的值和字典树的是几乎一样的(不过也有些不同,下面我会解释的)。存放的是当前所在第i个节点当下一个出现的字符为j的时候的节点位置。
2、fail[i] 这个和kmp中fail是一样的,当前第i个节点失配的话,那就去尝试匹配第fail[i] 里面存放的节点。

**以上就是字典树与kmp的合体,不过不同的是:1、在字典树中如果当前节点为i的话, 如果没有为j的节点, 那么next[i][j] == -1; 但是在AC自动机中里面会存放是,当前i节点的失配指针指向的节点中如果有同样j的节点那么就会next[i][j]指向它,如果其失配指针(fail[i])没有j节点的,那么就找fail[fail[i]] 中的j节点是否存在, 直到一直找到根为止。
2、在构建fail[i]的时候用的是这样的思路(BFS),如果在当前节点失配,那么就去找当前节点的父亲节点的失配指针指向的节点中是否有i节点,如果有就指向它,否则就在去找它的失配节点, 一直到找到或者到根为止。**

3、temp指针,其实在AC自动机里面每次沿着字典树走,每当走到一个新的节点,就会沿着当前节点的失配节点一直往上走,看是否有匹配的节点;
比如 字典树中有这两个字符 acdm, cd.
现在要求匹配的acdmk, 如果没有temp的话就只会找到acdm,但是有了temp指针,就能当走到acdm中的d的时候就可以匹配到cd了。

本人较懒没有附加图片,多多画图,和体会一下,应该就可以懂了的。

#include <iostream>#include <stdio.h>#include <algorithm>#include <cstring>#include <queue>#include <cmath>#include <math.h>#include <stack>#include <vector>using namespace std;#define Max_N 500010struct Trie{    int next[Max_N][26], fail[Max_N], end1[Max_N];    int root, L;    int newnode()    {        for (int i = 0; i < 26; i++)            next[L][i] = -1;        end1[L++] = 0;        return L-1;    }    void init()    {        L = 0;        root = newnode();    }    void insert(char buf[])    {        int len = strlen(buf);        int now = root;        for (int i = 0; i < len; i++) {            if (next[now][buf[i] - 'a'] == -1)                next[now][buf[i]-'a'] = newnode();            now = next[now][buf[i] - 'a'];        }        end1[now]++;    }    void build()    {        queue<int> q;        fail[root] = root;        for (int i = 0; i < 26; i++)            if (next[root][i] == -1)                next[root][i] = root;            else            {                fail[next[root][i]] = root;                q.push(next[root][i]);            }        while (!q.empty()) {            int now = q.front();            q.pop();            for (int i = 0; i < 26; i++)                if (next[now][i] == -1)                    next[now][i] = next[fail[now]][i];                else                {                    fail[next[now][i]] = next[fail[now]][i];                    q.push(next[now][i]);                }        }    }    int query(char buf[])    {        int len = strlen(buf);        int now = root;        int res = 0;        for (int i = 0; i < len; i++) {            now = next[now][buf[i] - 'a'];            int temp = now;            while (temp != root) {                res += end1[temp];                end1[temp] = 0;                temp = fail[temp];            }        }        return res;    }};char buf[1000010];Trie ac;int main(){    int T;    int n;    scanf("%d", &T);    while (T--) {        scanf("%d", &n);        ac.init();        for (int i = 0; i < n; i++) {            scanf("%s", buf);            ac.insert(buf);        }        ac.build();        scanf("%s", buf);        printf("%d\n", ac.query(buf));    }    return 0;}
原创粉丝点击