zoukankan      html  css  js  c++  java
  • Luogu P3808 【模板】AC自动机(简单版)

    传送门

    AC自动机(Aho-Corasick automaton)是一种优化的多模式串匹配的算法,它像是trie树和KMP的结合体。

    这个算法分为三部分:建立trie树,求fail,匹配。

    假设有cod,cos,ost,op几个单词。(这图画了好久好久好久)

    在普通trie树的基础上,像kmp一样处理出模式串的失配函数。(没有画出的,fail指向根0)

    建立trie树

    和普通的trie相同。

    void insert(char *s) {
        int len = strlen(s);
        int u = 0;
        for(int i = 0; i < len; i++) {
            int v = s[i]-'a';
            if(!trie[u].son[v]) trie[u].son[v] = ++num;
            u = trie[u].son[v];
        }
        trie[u].fin++;
    }

     

    求fail

    用bfs的方法,每次遍历'a'-'z',并将存在的节点压入队列。

    • trie上第一层fail = 0
    • x的son[i]的fail = x的fail的son[i]
    • 如果现在x不存在son[i],那么x的son[i] = x的fail的son[i]

    根据上述规则,得到以下代码

    void getf() {
        queue <int> q;
        for(int i = 0; i < 26; i++) {
            if(trie[0].son[i]) {
                trie[trie[0].son[i]].fail = 0;
                q.push(trie[0].son[i]);
            }
        }
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for(int i = 0; i < 26; i++) {
                if(trie[u].son[i]) {
                    trie[trie[u].son[i]].fail = trie[trie[u].fail].son[i];
                    q.push(trie[u].son[i]);
                } else
                    trie[u].son[i] = trie[trie[u].fail].son[i];
            }
        }
    }

    匹配

    本题中,要记录文本串中出现的模式串的数量。

    和kmp类似。每走到一个节点,将以这个节点为结尾的数量计入答案,并将模式串不断跳到fail。

    因为可能会形成环,需要记录是否访问过当前节点,防止重复。

    int query(char *s) {
        int len = strlen(s);
        int u = 0;
        int ans = 0;
        for(int i = 0; i < len; i++) {
            int v = s[i]-'a';
            u = trie[u].son[v];
            for(int j = u; j && !trie[j].vis; j = trie[j].fail) {
                ans += trie[j].fin;
                trie[j].vis = true;
            }
        }
        return ans;
    }

    还有什么暂时想不到了

    完整代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    #include<queue>
    using namespace std;
    
    const int maxn = 1e6+10;
    int n,num;
    char s[maxn];
    
    struct node {
        int son[26];
        int fin,fail;
        bool vis;
    } trie[maxn];
    
    void insert(char *s) {
        int len = strlen(s);
        int u = 0;
        for(int i = 0; i < len; i++) {
            int v = s[i]-'a';
            if(!trie[u].son[v]) trie[u].son[v] = ++num;
            u = trie[u].son[v];
        }
        trie[u].fin++;
    }
    
    void getf() {
        queue <int> q;
        for(int i = 0; i < 26; i++) {
            if(trie[0].son[i]) {
                trie[trie[0].son[i]].fail = 0;
                q.push(trie[0].son[i]);
            }
        }
        while(!q.empty()) {
            int u = q.front();
            q.pop();
            for(int i = 0; i < 26; i++) {
                if(trie[u].son[i]) {
                    trie[trie[u].son[i]].fail = trie[trie[u].fail].son[i];
                    q.push(trie[u].son[i]);
                } else
                    trie[u].son[i] = trie[trie[u].fail].son[i];
            }
        }
    }
    
    int query(char *s) {
        int len = strlen(s);
        int u = 0;
        int ans = 0;
        for(int i = 0; i < len; i++) {
            int v = s[i]-'a';
            u = trie[u].son[v];
            for(int j = u; j && !trie[j].vis; j = trie[j].fail) {
                ans += trie[j].fin;
                trie[j].vis = true;
            }
        }
        return ans;
    }
    
    int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; i++) {
            scanf("%s",s);
            insert(s);
        }
        getf();
        scanf("%s",s);
        printf("%d",query(s));
        return 0;
    }
  • 相关阅读:
    浅析[53300] FATAL: remaining connection slots are reserved for non-replication superuser connections
    浅析Web安全漏洞里的X-Frame-Options、X-XSS-Protection、X-Content-Type-Options响应头配置以及如何通过nginx配置避免
    浅析SpringSecurity的方法级安全管控
    浅析mybatis的全局配置文件mybatis-config.xml各配置的意义
    字节序--大端字节序和小端
    【转】go语言中int和byte转换方式
    [转]float32数据在内存中的存储方法
    go语言复制一个struct 对象
    一个table 中 可以有多个tbody. table 可以嵌套
    【转】rpc框架设计
  • 原文地址:https://www.cnblogs.com/mogeko/p/11322321.html
Copyright © 2011-2022 走看看