zoukankan      html  css  js  c++  java
  • AC自动机

    看这数据结构的名字就必须学习一个啊~~

    AC自动机就是Trie和kmp的结合。

    kmp是查询一个字符串,而自动机用于多个字符串的查询,比如给一篇文章和许多字符串,问有多少字符串出现过等。

    由于是一般是模板题,先上板啦,在kuangbin大大那里搬过来的。

    是HDU2222 的AC代码

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <queue>
    using namespace std;
    
    const int N = 500010;   // 字符串个数*字符串长度
    const int A = 26;       // 不同字符个数
    const int M = 10000;    // 字符串个数
    
    struct ACAutomata {
    
        int next[N][A], fail[N], end[N];
        int root, L;
        int newNode()
        {
            for (int i = 0; i < A; ++i) next[L][i] = -1;
            end[L] = 0;
            return L++;
        }
        void init()
        {
            L = 0;
            root = newNode();
        }
        void insert(char buf[])
        {
            int len = strlen(buf);
            int now = root;
            for (int i = 0; i < len; ++i) {
                int ch = buf[i] - 'a';
                if (next[now][ch] == -1) next[now][ch] = newNode();
                now = next[now][ch];
            }
            end[now]++;
        }
        void build()
        {
            queue<int> Q;
            fail[root] = root;
            for (int i = 0; i < A; ++i) {
                if (next[root][i] == -1) {
                    next[root][i] = root;
                } else {
                    fail[ next[root][i] ] = root;
                    Q.push( next[root][i] );
                }
            }
            while (Q.size()) {
                int now = Q.front();
                Q.pop();
                for (int i = 0; i < A; ++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) {
                int ch = buf[i] - 'a';
                now = next[now][ch];
                int tmp = now;
                while (tmp != root) {
                    res += end[tmp];
                    end[tmp] = 0;
                    tmp = fail[tmp];
                }
            }
            return res;
        }
    
    } ac;
    
    
    char buf[1000010];
    int main()
    {
        int T, n;
        scanf("%d", &T);
        while (T--) {
            scanf("%d", &n);
            ac.init();
            while (n--) {
                scanf("%s", buf);
                ac.insert(buf);
            }
            scanf("%s", buf);
            ac.build();
            printf("%d
    ", ac.query(buf));
        }
        return 0;
    }

    L就是AC自动机的状态数。

    以bfs的顺序遍历trie。

    fail适配指针,fail[i]指第i个状态的下一个失配后转移的位置。没有可以转移的位置就为root。

    end[i]表示以状态i为结尾的字符串个数。

    query()里面的while用来求重复的字符串,例如she包含he。

    类似模板题HDU2896 和 HDU3065 因为没有相等的字符串,end[i]来记录以i结束的字符串id就可以了。

  • 相关阅读:
    c++调用win32API控制打印机打印
    php socket 通信
    [SDOI2015][BZOJ3991] 寻宝游戏|set|dfs序|虚树|树上倍增LCA
    [NOI2015][BZOJ4195] 程序自动分析|并查集|离散化
    [NOI2015][BZOJ4196] 软件包管理器|树链剖分
    [HEOI2014][BZOJ3611] 大工程|虚树|树型dp|dfs序|树上倍增LCA
    [Usaco2007 Mar][BZOJ1638] Cow Traffic 奶牛交通|动态规划
    [HDU2222]Keywords Search|AC自动机
    [POI2007][BZOJ1103] 大都市meg|dfs序|树状数组
    [Usaco2007 Dec][BZOJ1690] 奶牛的旅行|分数规划|二分|SPFA
  • 原文地址:https://www.cnblogs.com/wenruo/p/5616210.html
Copyright © 2011-2022 走看看