1. 程式人生 > >AC自動機學習筆記

AC自動機學習筆記

ide .net detail 生成器 bzoj2434 not o-c int 套路

AC自動機

Tags:字符串
作業部落


一、概述

\(Aho-Corasic\ automaton\),中文名\(AC\)自動機,是\(Trie\)圖的一種,實現高效多串匹配單串的一種字符串算法
跟蹤dalao的blog
\(Trie\)樹上令一個點表示從根到它的串,那麽一個點的fail指向和它擁有最長後綴的串(所以可以指向\(0\)

二、題單

  • [x] [luogu3808]【模板】AC自動機(簡單版) https://www.luogu.org/problemnew/show/P3808
  • [x] [luogu3796]【模板】AC自動機(加強版)https://www.luogu.org/problemnew/show/P3796
  • [ ] [CJOJ1435] 【模板題 USACO】AC自動機 https://oj.changjun.com.cn/problem/detail/pid/1435
  • [x] [HDU2296]Ring https://vjudge.net/problem/HDU-2296#author=prayerhgq
  • [x] [BZOJ1030][JSOI2007]文本生成器 https://www.luogu.org/problemnew/show/P4052
  • [x] [BZOJ3172][TJOI2013]單詞 https://www.luogu.org/problemnew/show/P3966
  • [x] [Luogu2444][POI2000]病毒 https://www.luogu.org/problemnew/show/P2444
  • [x] [BZOJ1009][HNOI2008]GT考試 https://www.luogu.org/problemnew/show/P3193
  • [x] [BZOJ3530][SDOI2014]數數 https://www.luogu.org/problemnew/show/P3311
  • [x] [Luogu3121][USACO15FEB]審查Censoring https://www.luogu.org/problemnew/show/P3121
  • [x] [BZOJ1212][HNOI2004]L語言 https://www.luogu.org/problemnew/show/P2292
  • [x] [Luogu3041][USACO12JAN]視頻遊戲的連擊Video Game Combos https://www.luogu.org/problemnew/show/P3041
  • [ ] [BZOJ2434]阿貍的打字機 https://www.luogu.org/problemnew/show/P2414
  • [ ] [BZOJ2754]喵星球上的點名 https://www.luogu.org/problemnew/show/P2336

    三、做題經驗

    1
    用來多串匹配單串或多串,效率高於\(KMP\)(可以代替),但是字符集很大時候需要大空間或用時間換空間(開\(set\)
    2
    套路:\(dp[i][j]\)表示到第\(i\)號節點(長串匹配到\(i\)),匹配長度為\(j\)(短串匹配到\(j\))的方案數啥的

    四、Tip

    ! \(Fail\)是一棵樹,但是\(AC\)自動機是\(Trie\)圖,可以存在環(病毒)
    ! 構造數據的時候,可以檢查自己寫的\(AC\)自動機是否可以從第一位開始匹配

    五、模板

    洛谷3808模板1
    首先建出\(Trie\)樹(\(Build\)),然後通過\(BFS\)算出\(Fail\),再進行匹配

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int MAXN=1000100;
    struct Node{int ch[26],fail,end;}t[MAXN];
    char s[MAXN];
    int N,node;
    queue<int> Q;
    void Build()
    {
    int len=strlen(s),x=0;
    for(int i=0;i<len;i++)
    {
        if(!t[x].ch[s[i]-'a']) t[x].ch[s[i]-'a']=++node;
        x=t[x].ch[s[i]-'a'];
    }
    t[x].end++;
    }
    void Get_Fail()
    {
    for(int i=0;i<26;i++) if(t[0].ch[i]) Q.push(t[0].ch[i]);
    while(!Q.empty())
    {
        int x=Q.front();Q.pop();
        for(int i=0;i<26;i++)
            if(t[x].ch[i])
            {
                t[t[x].ch[i]].fail=t[t[x].fail].ch[i];
                Q.push(t[x].ch[i]);
            }
            else t[x].ch[i]=t[t[x].fail].ch[i];
    }
    }
    int AC()
    {
    int len=strlen(s),x=0,ans=0;
    for(int i=0;i<len;i++)
    {
        x=t[x].ch[s[i]-'a'];
        for(int p=x;p&&~t[p].end;p=t[p].fail)
            ans+=t[p].end,t[p].end=-1;
    }
    return ans;
    }
    int main()
    {
    cin>>N;while(N--){scanf("%s",s);Build();}
    Get_Fail();scanf("%s",s);
    printf("%d\n",AC());return 0;
    }

AC自動機學習筆記