是一種數學模型,大概就是由一堆狀態和狀態轉移規則等東西構成,能與外界交換資訊,並改變動作。
這個是理論上的東西,了解就行,對ac自動機的理解沒有大影響。
通俗的講就是在trie上做kmp,處理多模式串匹配問題。
trie 的每個結點就是乙個狀態,根結點是初始狀態。
ac自動機的行為被定義為一下3個函式:
1. next函式 ch(q,a):返回從當前狀態q走值為a的邊後所到達的狀態。如果根節點沒有值為a的邊,那麼ch(0,a)=0,(就是說:當讀入不匹配的字元時,自動機保持在初始狀態)
如果從結點q出發有一條邊值為a到達結點v,那麼 ch(q,a)=v,否則ch(q,a)=φ。
2. fail函式 fail(q):返回從狀態q(q!=root)匹配錯誤時要轉移到的狀態
記l(q)表示trie上q節點對於的字串,
如果l(v)是l(q)的乙個字尾,且是最長的字尾,則fail(q)=v(kmp的思想)。
fail(q)總是能返回乙個狀態,因為l(root)=φ是任何模式串的字首
3. output函式out(q):輸出在狀態q時,所有匹配的模式串。
上面的描述比較形式化。簡單來說:
先把所有待匹配串插入到一顆trie中。
對於每個節點,我們需要額外計算一些資訊:
fail指標:如上所述,類似kmp中的next表。
cnt : 若這個位置是某個模式串的結尾,就cnt++。
last指標:指向沿著當前節點的fail指標往回走,第乙個遇到的cnt>0的節點。是用於output的。
假設我們已經構造出了這些資訊。考慮如何進行匹配,大概流程是這樣的:
根據目標串乙個乙個字元在trie上走,
每走到乙個節點,執行一次output(順著last指標往後累加答案)。走到下個節點時,如果ch(p,s[i])不為空則直接走過去,否則沿著fail指標走,直到匹配成功或者到初始狀態(還是kmp)
注意到「沿著fail指標走,直到匹配成功或者到初始狀態」這個過程較繁瑣,而且只有ch(p,s[i])為空時才會執行,就想到可以優化一下,直接把ch(p,s[i])指到要跳到的節點。
**如下:
int find(p_node p)
int query(char* s)
回到如何構造這些資訊,顯然都可以一次對trie的bfs遍歷實現,具體對於p的某個兒子v:
v->fail=p->fail->ch[i];
v->last=(v->fail->cnt?v->fail:v->fail->last);
要注意的是root的直接兒子的fail和last都指向root。
理解定義後還是比較顯然的。
模板題pdu2222**:
#include
#include
#include
#include
using namespace std;
struct node base[500000], *len, nil, *null=&nil, *root;
typedef node* p_node;
p_node newnode(node* son=null)
void insert(p_node &p,char *now)
insert(p->ch[(*now)-'a'],now+1);
}queueque;
void build() else root->ch[i]=root;
while(!que.empty()) else p->ch[i]=p->fail->ch[i];
}}int find(p_node p)
int query(char* s)
int _test,n,m;
char s[1000005];
int main()
return
0;}
AC自動機學習筆記
ac自動機是基於字典樹和fail指標來快速一類解決多串匹配的問題。先用所有模式串建乙個字典樹。然後用bfs搞出每個節點的fail指標。fail指標是指向 和當前 字首的字尾有最長匹配的字首。洛谷3808 掃文字串的時候,標記一下訪問過的字典樹上的節點。include using namespace ...
AC自動機學習筆記
title ac自動機學習筆記 date 2020 08 31 15 53 40 tags 8月的最後一天,還是完成了ac自動機的學習。在熟練掌握了kmp後,我發現ac自動機並沒有想象的那麼難,既不難理解,也不難實現,於是決定寫點東西記錄一下。本篇主要談談ac自動機的理論,思想。首先我們必須要明確乙...
AC自動機學習筆記
先簡單複習一下學習ac自動機所需要的字首知識。字首知識 1 trie樹 字典樹,也稱trie樹,字首樹,主要用於儲存大量的字串以及查詢操作。對於trie樹,一般有兩個操作 舉個例子,對於這樣幾個字串,我們看他們在trie樹中是如何儲存的 這裡需要注意,字元是邊,而不是節點,但都是一一對應的 int ...