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就可以了。

  • 相关阅读:
    MySQL5.7安装详细教程
    Java之GUI编程
    Java基础
    生成JavaDoc文档
    SpringtMVC运行流程:@RequestMapping 方法中的 Map、HttpServletRequest等参数信息是如何封装和传递的(源码理解)
    SpringCache @Cacheable 在同一个类中调用方法,导致缓存不生效的问题及解决办法
    Spring源码学习:第1步--在Spring源码中添加最简单的Demo代码
    Spring源码学习:第2步--使用SLF4j+Log4j日志框架替换掉其自身的commons-logging日志框架
    Spring源码学习:第0步--环境准备
    JasperReport报表
  • 原文地址:https://www.cnblogs.com/wenruo/p/5616210.html
Copyright © 2011-2022 走看看