自动AC机

来源:互联网 发布:msbs步枪 知乎 编辑:程序博客网 时间:2024/05/16 18:21

自动AC机就是trie上的kmp,由于trie从跟到任意节点都是模式串中存在的一个子串,所以可以类比KMP,从每个节点向另一个节点连一条失配边(KMP的失配边就是next数组,因此可视为trie为一条链)。实现的过程中有一点优化,就是如果一个点的某个儿子不存在,把他连向fail指针的该儿子。这样就不用写循环了,清爽了很多。

模板题:hdu2222

题意:给定一个大字符串和若干模式串,求有多少模式串在大字符串中出现过。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAXN = 1000005;const int MAXS = 10005 * 50;int T, N;char s1[55], s[MAXN];int que[MAXS];struct Trie{    int ch[MAXS][26], cnt[MAXS], fail[MAXS];    bool vis[MAXS];    int ncnt;    void init()    {        for (int i = 0; i<26; ++i)            ch[0][i] = 1;        for (int i = 1; i<=ncnt; ++i) {            for (int j = 0; j<26; ++j) ch[i][j] = 0;            vis[i] = 0, fail[i] = cnt[i] = 0;        }        ncnt = 1;    }    void ins(char *s)    {        int p = 1;        for (int i = 0, c; s[i]; ++i)        {            c = s[i] - 'a';            if (!ch[p][c]) p = ch[p][c] = ++ncnt;            else p = ch[p][c];        }        ++cnt[p];    }    void build()    {        int l = 0, r = 0, t, p, i;        fail[que[l] = 1] = 0;        while (l <= r) {            t = que[l ++];            for (i = 0; i < 26; ++i) {                if (!ch[t][i]) continue;                p = fail[t];                while (!ch[p][i]) p = fail[p];                fail[ch[t][i]] = ch[p][i];                que[++r] = ch[t][i];            }        }    }    int quary(char *s)    {        int k = 1, c, ans = 0;        for (int i = 0; s[i]; ++i) {            vis[k] = 1;            c = s[i] - 'a';            while (!ch[k][c]) k = fail[k];            k = ch[k][c];            if (!vis[k])                for (int j = k; j; j = fail[j])                    ans += cnt[j], cnt[j] = 0;        }        return ans;    }} ac;int main(){    scanf("%d", &T);    while (T--) {        scanf("%d", &N);        ac.init();        while (N --)            scanf("%s", s1), ac.ins(s1);        ac.build();        scanf("%s", s);        printf("%d\n", ac.quary(s));    }    return 0;}


0 0