title: ac自動機學習筆記
date: 2020-08-31 15:53:40
tags:
8月的最後一天,還是完成了ac自動機的學習。在熟練掌握了kmp後,我發現ac自動機並沒有想象的那麼難,既不難理解,也不難實現,於是決定寫點東西記錄一下。
本篇主要談談ac自動機的理論,思想。
首先我們必須要明確乙個問題,即ac自動機到底是幹嘛的,我在查閱了許多文章與部落格後發現他們並沒有把這個問題闡釋清楚,這裡我解釋一下。
我們知道,kmp演算法可以在o(n)時間內進行對模式串的匹配工作,但kmp演算法每次只能處理乙個模式串,而ac自動機藉由字典樹與fail指標(類似kmp中的next陣列),可以在o(n)時間內完成對若干模式串的匹配工作,包括檢查是否存在、出現了幾次等等。ac自動機有乙個常見的應用,即文字詞頻統計。
想學習掌握ac自動機,必須先掌握字典樹,即trie樹,並理解kmp的核心思想。
字典樹又稱單詞查詢樹,trie樹,是一種樹形結構。典型應用是用於統計,排序和儲存大量的字串(且不僅限於字串)。它的優點是:利用字串的公共字首來減少查詢時間,最大限度地減少無謂的字串比較,查詢效率比雜湊樹高。
字典樹的實現形式多樣,用起來也很靈活,後面會給乙個比較簡單的板子。
字典樹可以單獨使用,也可以包含進其他複雜資料結構中。
在ac自動機中,我們先將需要查詢的單詞全部插入到字典樹中,再藉此構造fail指標,然後進行模式匹配。
我們知道,kmp的核心思想就是利用已經匹配過的部分,減少重複匹配工作,避免回溯,fail指標的作用也與此類似。如果當前點匹配失敗,則將指標轉移到fail指標所指向的地方繼續進行匹配。fail指標依靠的是什麼?是當前模式串字尾和fail指標指向的模式串部分字首相同。是不是很像next陣列?next陣列的定義就是最長公共前字尾,而這裡我們可以理解為當前模式串與fail指標指向的模式串的公共前字尾,而這個公共前字尾,就是我們通過fail指標可以避免重複匹配的部分,並且是最長的。這樣,我們只要從頭到尾遍歷一遍匹配字串,就能完成所有模式串的匹配工作(這裡要注意的一點是字典樹里是沒有相同單詞的,或者說相同單詞我們通過前面**裡的cnt陣列儲存下來了)。
匹配過程也與kmp類似。我們從匹配串的開頭開始,將每個字元與字典樹中的字元匹配,需要注意的是:
在單次匹配中,如果當前字元與字典樹中的字元匹配成功,那麼將答案加上字典樹中在這個字元結尾的單詞的數量。
字典樹中可能存在這樣的單詞,是當前模式串的字尾,因此我們還要通過fail指標找到它,將它出現的次數也統計上,直到fail指標指向根,或走到的節點已訪問過。
在構建fail指標的過程中,如果當前節點不存在某個字母的兒子節點,我們會將其指向其fail指標所指向的位置。因此在單次匹配中若匹配失敗,我們仍然可以順著字典樹繼續匹配,實際上是完成了一次順著fail指標轉移的操作。
int ch[maxn][26
];//字典樹
int cnt[maxn]
;//單詞出現次數
int sz;
void
init()
void
insert
(char str,
int len)
//插入字串
u = ch[u]
[v];
} cnt[u]++;
//在這裡我們可以建立乙個int-string的對映,以通過節點序號得知這個點是哪個單詞的結尾
}int
findstr
(char str,
int len)
//查詢字串
return cnt[u]
;}
int fail[maxn]
;void
getfail()
}while
(!q.
empty()
)else
ch[now]
[i]= ch[fail[now]
][i];}
}}
int
query
(char str,
int len)
}return ans;
}
9.11更新
在刷了一定量的題後,我對ac自動機有了新的理解,我發現ac自動機本質上其實就是在字典樹上加邊,從而構成了一張狀態轉換圖,圖上的每個節點都可以表示乙個字串。我們在進行模式匹配時,實質上就是在進行狀態轉換。藉由這個狀態轉換圖,ac自動機可以與很多其他的演算法知識結合起來,比如動態規劃,最短路,矩陣快速冪等等。拿動態規劃舉例,我們在進行dp時常常會加一維,表示當前所在的狀態轉換圖節點,而在使用ac自動機構成狀態轉換圖時,我們可以在節點上附加資訊,比如有時題目要求是不能存在某個串,那麼我們可以在節點上標記一下,這個點不能到達;有時題目要求出現若干個串,在串的數量不大時我們可以利用狀態壓縮,用整形資料的每乙個二進位制位表示某個字串是否出現過,這個可以放在dp陣列的第三維,以表示當前匹配狀態,既可以表示某個串是否出現過,也可以得到出現過幾個不同的串。在進行dp時,狀態轉移方程就多了一維以表示當前所在的狀態轉換圖節點,這樣我們就省掉了繁雜的字串匹配工作,直接借助圖進行狀態轉換就行了。
我們知道構建fail指標實際上就是構建狀態轉換圖的過程,而在構建fail指標時我們也可進行一定的修改。我們知道,fail指標指向的實際上是當前節點表示字串的最長字尾,那麼我們就可以在當前節點上標記一下,表示當匹配到這個節點時,fail指標指向的那個節點所代表的字串也被匹配到了。而求fail指標時是用的bfs思想,因此我們可以逐層的進行處理。
有時我們要做的是這些串不出現,那麼我們只要讓標記陣列進行邏輯或一下就可以了,如果當前節點所包含的字尾中有不能出現的字串,那當前節點無疑也不能走。同樣的,有時我們需要知道走到當前節點時,匹配到了哪些串。在一開始,我們是通過fail指標逐次的往根節點走,實際上我們可以利用上面說到的狀態壓縮思想,假設字串編號為i,那標記就可以是1《一般情況下這類問題的資料規模都不會很大,比如要讓若干個串全部未出現過,那構造的目標串長度一般就10e4-10e5左右,dp就可以解決,但有時會遇到長度非常大的情況,我們就得考慮別的方法了。就拿這個問題舉例,也就是poj2778,目標串長度+1時我們就可以理解為在狀態轉換圖上走向了乙個節點,這樣問題就轉化為在狀態轉換圖中從根結點開始長度為n的,且不經過某些點的不同路徑數量,這裡的某些點即不能出現的串的終點所在節點。於是我們可以構造出狀態轉移矩陣,表示節點i和節點j之間有若干條邊可走,接著就可以用矩陣快速冪加速轉移過程了。
AC自動機 學習筆記
是一種數學模型,大概就是由一堆狀態和狀態轉移規則等東西構成,能與外界交換資訊,並改變動作。這個是理論上的東西,了解就行,對ac自動機的理解沒有大影響。通俗的講就是在trie上做kmp,處理多模式串匹配問題。trie 的每個結點就是乙個狀態,根結點是初始狀態。ac自動機的行為被定義為一下3個函式 1....
AC自動機學習筆記
ac自動機是基於字典樹和fail指標來快速一類解決多串匹配的問題。先用所有模式串建乙個字典樹。然後用bfs搞出每個節點的fail指標。fail指標是指向 和當前 字首的字尾有最長匹配的字首。洛谷3808 掃文字串的時候,標記一下訪問過的字典樹上的節點。include using namespace ...
AC自動機學習筆記
先簡單複習一下學習ac自動機所需要的字首知識。字首知識 1 trie樹 字典樹,也稱trie樹,字首樹,主要用於儲存大量的字串以及查詢操作。對於trie樹,一般有兩個操作 舉個例子,對於這樣幾個字串,我們看他們在trie樹中是如何儲存的 這裡需要注意,字元是邊,而不是節點,但都是一一對應的 int ...