[洛穀日報第44期]強勢圖解AC自動機

2020-12-11 洛谷科技

AC自動機·Aho-Corasick_automation

前置技能(宣傳一下自己的Blog)

KMP字符串匹配(http://www.yaoyaojy.tk/index.php/archives/37/)TRIE字典樹(http://www.yaoyaojy.tk/index.php/archives/38/)

簡介

看dalao們AC自動機的Blog,大多數奆奆都會感性地說:AC_automation = KMP+TRIE然而在作者重蹈覆轍輾轉反側n次後才明白,這東西說了等於沒說。AC自動機是一種有限狀態自動機(說了等於沒說),它常被用於多模式串的字符串匹配。在學完AC自動機,筆者也總結出一句說了等於沒說的話:AC自動機是以TRIE的結構為基礎,結合KMP的思想建立的。

建立AC自動機

建立一個AC自動機通常需要兩個步驟:

基礎的TRIE結構:將所有的模式串構成一棵Trie。KMP的思想:對Trie樹上所有的結點構造失配指針。

然後就可以利用它進行多模式匹配了。

TRIE構建

和trie的insert操作一模一樣(強調!一模一樣!)因為我們只利用TRIE的結構,所以只需將模式串存入即可。

構造失配(fail)指針

在講構造以前,先來對比一下這裡的fail指針與KMP中的next指針:

共同點-兩者同樣是在失配的時候用於跳轉的指針。不同點-KMP要求的是最長相同真前後綴,而AC自動機只需要相同後綴即可。因為KMP只對一個模式串做匹配,而AC自動機要對多個模式串做匹配。有可能fail指針指向的結點對應著另一個模式串,兩者前綴不同。也就是說,AC自動機在對匹配串做逐位匹配時,同一位上可能匹配多個模式串。因此fail指針會在字典樹上的結點來回穿梭,而不像KMP在線性結構上跳轉。

下面介紹構建fail指針的基礎思想:(強調!基礎思想!基礎!)

構建fail指針,可以參考KMP中構造next數組的思想。我們利用部分已經求出fail指針的結點推導出當前結點的fail指針。具體我們用BFS實現:如果結點fail[p]通過字母c連接到的子結點w存在:如果fail[p]通過字母c連接到的子結點w不存在:則讓u的fail指針指向這個結點w(fail[u]=w)。相當於在p和fail[p]後面加一個字符c,就構成了fail[u]。那麼我們繼續找到fail[fail[p]]指針指向的結點,重複上述判斷過程,一直跳fail指針直到根節點。如果真的沒有,就令fail[u]=根節點。考慮字典樹中當前的節點u,u的父節點是p,p通過字符c的邊指向u。假設深度小於u的所有節點的fail指針都已求得。那麼p的fail指針顯然也已求得。我們跳轉到p的fail指針指向的結點fail[p];如此即完成了fail指針的構建。

下面放一張GIF幫助大家理解:對字典樹{i,he,his,she,hers}構建fail指針:

黃色結點表示當前的結點u,綠色結點表示已經BFS遍歷完畢的結點,紅/橙色的邊表示fail指針。

AC_automation_gif_b_3.gif我們重點分析結點6的fail指針構建:

AC_automation_6_9.png找到6的父節點5,5的fail指針指向10,然而10結點沒有字母's'連出的邊;所以跳到10的fail指針指向的結點0,發現0結點有字母's'連出的邊,指向7結點;所以fail6=7.

另外,在構建fail指針的同時,我們也對TRIE中模式串的結尾構建fail指針。這樣在匹配到結尾後能自動跳轉到下一個匹配項。具體見代碼實現。

從代碼深入剖析

代碼總框架

字典樹or字典圖

關於insert()筆者不做分析,先來看build():

這裡的字典樹根節點為0,我們將根節點的子節點一一入隊。

Q1-等等,為什麼不將根節點入隊,非要將它的子節點入隊?

然後開始BFS:

如果字符i對應的子節點存在,我們就將這個子節點的fail指針賦值為`fail[k]`的字符i對應的結點。

Q2-不是應該用while循環,不停的跳fail指針,判斷是否存在字符i對應的結點,然後賦值嗎?怎麼一句話就完了?

否則,k結點沒有字符i對應的子節點,就將fail[k]的字符i對應的子節點編號賦值給k

Q3-等等,說好的字典樹呢?怎麼將fail[k]的子節點直接賦成k的子節點去了?

每次取出隊首的結點k。注意,結點k本身的fail指針已經求得,我們要求的是k的子節點們的fail指針。

然後遍歷字符集(這裡是0-25,對應a-z):

這三個Questions構成了fail指針構建的精髓。

Answer to Q1

若將根節點入隊,則在第一次BFS的時候,會將根節點的子節點的fail指針標記為本身。

而將根節點的子節點入隊,也不影響算法正確性(因為fail指針初始化為0)

Answer to Q2&Q3

Q2與Q3的代碼是相輔相成的。

簡單地來講,我們將fail指針跳轉的路徑做了壓縮(就像併查集的路徑壓縮),使得本來需要跳很多次fail指針變成跳一次。

而這個路徑壓縮的就是Q3的代碼在做的事情之一。

我們將之前的GIF圖改一下:

藍色結點表示BFS遍歷到的結點k,深藍色、黑色的邊表示執行完Q3代碼連出的字典樹的邊。

可以發現,眾多交錯的黑色邊將字典樹變成了字典圖。

圖中省略了連向根節點的黑邊(否則會更亂)。

我們重點分析一下結點5遍歷時的情況:

顯然,本來應該跳2次才能找到7號結點,但是我們通過10號結點的黑色邊直接通過字母s找到了7號結點。

因此,Q2結合了Q3的代碼,就能在O(1)的時間內對單個結點構造fail指針。

這就是build完成的兩件事:構建fail指針和建立字典圖。這個字典圖也會在查詢的時候起到關鍵作用。

多模式匹配的真諦

接下來分析匹配函數query():

循環遍歷匹配串,p在字典樹上跟蹤當前字符。

利用fail指針找出所有匹配的模式串,累加到答案中。然後清0。

對e[j]取反的操作用來判斷e[j]是否等於-1。

Q-讀者可能納悶了:你這裡的p一直在往字典樹後面走,沒有跳fail指針啊!這和KMP的思想不一樣啊,怎麼匹配得出來啊

Answer to Q

還記得剛才的字典圖嗎?事實上你並不是一直在往後跳,而是在圖上穿梭跳動。比如,剛才的字典圖:

我們從根節點開始嘗試匹配ushersheishis,那麼p的變化將是:

紅色結點表示p結點,粉色箭頭表示p在字典圖上的跳轉,淺藍色的邊表示成功匹配的模式串,深藍色的結點表示跳fail指針時的結點。

其中的部分跳轉,我們利用的就是新構建的字典圖上的邊,它也滿足後綴相同(sher和her),所以自動跳轉到下一個位置。

綜上,fail指針的意義是,在匹配串同一個位置失配時的跳轉指針,這樣就利用fail指針在同一位置上進行多模式匹配,匹配完了,就在字典圖上自動跳轉到下一位置。

總結-這就是AC自動機

到此,你已經理解了整個AC自動機的內容。我們一句話總結AC自動機的運行原理:構建字典圖實現自動跳轉,構建失配指針實現多模式匹配。你曾經憧憬的,「能自動AC算法題目」的AC自動機,已經掌握了。

完整代碼

洛谷AC自動機模板題簡單版(https://www.luogu.org/problemnew/show/P3808)

練習

洛谷模板題x2

完結撒花

本文發布於洛穀日報,特約作者:水手hwy

原文地址:https://www.luogu.org/blog/42196/qiang-shi-tu-xie-ac-zi-dong-ji

相關焦點

  • 字符串匹配算法之 AC 自動機
    將Trie樹上的每一個點都加上fail指針,它就變成了AC自動機。AC自動機其實就是Trie + KMP。因此根據補上一些失配指針,我們的AC自動機應該長成這樣的。function createFail(ac) {    var root = ac.root;    var queue = [root]; //root所在層為第0層    while (queue.length) {        //廣度優先遍歷        var node = queue.shift
  • [洛穀日報第35期]淺談自適應Simpson法
    返回的面積則是 S_1+S_2+\frac{S_1+S_2-S_0}{15}附程序:3 後記這篇文章筆者寫了4h吧,內容還算簡單,希望各位能夠愉快地享用~( ̄▽ ̄)~*btw,洛谷北京:清華大學出版社,2012本文發布於洛穀日報,特約作者:khong原文地址:https://khong-biet.blog.luogu.org/adaptive-Simpsons-rule
  • [洛穀日報第53期]淺談一些求近似值的方法
    一句話概括就是在縮小區間後可以只計算一個試點坐標,從而保證最優操作流程如下(和二分法類似)附程序:讀者們可以在洛谷牛頓迭代法先說說這個方法的過程稍加計算便得到了既然是迭代,那麼自然就有其中x_n代表第n
  • [洛穀日報第19期]Codeforces遊玩攻略
    如何讀懂排行榜比賽排行榜圖解:比賽結束後Codeforces系統會自動根據您的比賽排名為您計算Rating。當這場比賽您的成績比較好您就增加rating,否則可能會降。6.當然還有高Rating啦本文發布於洛穀日報,特約作者:ezoixx130原文地址:https://www.luogu.org/blog/ezoixx130/codeforces-tutorial
  • [洛穀日報第46期]線段樹的擴展之淺談zkw線段樹
    0 閱讀本文前請先閱讀【洛穀日報#4】淺談線段樹(https://pks-loving.blog.luogu.org/senior-data-structure-qian-tan-xian-duan-shu-segment-tree)本文主要是上面文章的延伸,所以上文有講的東西本文就不詳細講了QwQ筆者的測試代碼可能寫醜了
  • [洛穀日報第29期]OI中可以用到的Linux基礎教程
    Linux基礎教程●前置系統:任意Linux(不用NOI Linux也沒問題,我用的是deepin),如果沒有裝,而且你用的是win10,請看往期的洛穀日報:練習Linux?4.wine下的TIM、QQ了解一下(強勢安利一波deepin、完美wine模擬)。完結撒花!★,°:.☆( ̄▽ ̄)/$:.°★ 。
  • [洛穀日報第38期]淺談如何在 Codeforces 下分
    戲劇性的是,在errorerror失誤漲rating這場,newbie314159通過Hack Failed次強勢墊底,為自己的CF下分路又添上了一份力。6. 結語下分也是一種技術。給本文發布於洛穀日報,特約作者:OwenOwl原文地址:https://mcfx0.blog.luogu.org/codeforces-negative
  • [洛穀日報第79期]二進位與位運算
    簡單來說,二進位基數為 2 ,只有 1 和 0二進位轉十進位對於一個二進位數,他的十進位數為從左往右的每一位乘上該位數的 2 次方(從第0位開始),例如 十進位轉二進位舉個例子10101(21) & 11100(28) = 10100{20}我們可以用 & 運算判斷一個數是奇數還是偶數,當 x 為奇數時, x 二進位下的第 0 位一定是 1 ,否則為 0 。我們讓 x & 1 ,就可以知道 x 的奇偶性了。
  • [洛穀日報第22期]可以代替線段樹的樹狀數組?
    假設現在進行到了第i項,那麼顯然易得(看圖):該數控制的a數組的元素是 [i-lowbit(i)+1,i]。設L=i-lowbit(i)+1,R=i。如果l<=L<=r那麼就將c[L]加入最值的判斷中,接著L--……,否則的話就只對第R個元素加入,然後R--……,代碼如下:顯然,時間複雜度是 O(logn*logn)O(lognlogn) 的。
  • [洛穀日報第45期]談談關於初賽的那些事
    下面主要提一下數學知識和CCF讚歌相關的,相信大家在其他的洛穀日報裡能夠看到許多圖論與數據結構相關的內容,而硬體知識與計算機發展史也應該已經有所了解。id=657&hash=64DD5A)7月16日-22日,由中國計算機學會(CCF)主辦,長沙市雅禮中學承辦的第35屆全國青少年信息學奧林匹克競賽(NOI2018)在星城長沙隆重舉行。(點燃夢想,燃燒激情——NOI2018在長沙順利舉行http://www.noi.cn/newsview.html?
  • [洛穀日報第4期]淺談線段樹——Segment Tree
    我實在是不想再碼一遍了qwq最後貼~~高清無碼的~~標程:(還有,輸入大數據一定不要用不加優化的cin/cout啊)本文發布於洛穀日報
  • [洛穀日報第21期]你不知道的CPP11新語法
    傳送門鳴謝:本文參考了以下資料,感謝作者的辛勞付出:https://www.jianshu.com/p/2d44dae53910https://blog.csdn.net/zdy0_2004/article/details
  • [洛穀日報第59期]我有獨特的騙分技巧
    不急,來看道題:洛谷P1463 POI2002,HAOI2007 反素數(https://www.luogu.org/problemnew/show/P1463)這道題可謂是經典的打表題(個人覺得搜索簡單些),但是也不能無腦直接『打出答案』,比如我一開始的打表思路就是如下的偽代碼:
  • 【第1790期】圖解Event Loop
    關於本文譯者:@Logan70譯文:https://github.com/logan70/Blog/issues/25作者:@Lydia Hallie原文:https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif為你推薦【第1405期】瀏覽器的 Event Loop
  • 常用圍棋術語總結丨丨動態圖解(第2期)
    大家好,我是白夕,上周,我們總結了一些常用圍棋術語,現在我們來更第2期了。下方是第1期的連結,需要的同學可以自行點擊閱讀哦。常用圍棋術語總結丨丨動態圖解(第1期)大家只要在下棋的時候,多使用圍棋術語,自然更容易學會了(未完待續)我們的第2期的圍棋術語總結,就到這裡了,下一期還會繼續更新的。喜歡我們的,可以評論、點讚(在看)、轉發,素質三連,謝謝大家,晚安。
  • 【第1589期】圖解 Map、Reduce 和 Filter 數組方法
    juejin.im/post/5caf030d6fb9a068736d2d7c作者:Una Kravets作者:https://css-tricks.com/an-illustrated-and-musical-guide-to-map-reduce-and-filter-array-methods/校對者:@Endone、@Reaper622為你推薦【第1431
  • 【聽力練習第44期】Corny是'玉米的'意思嗎?
    歡迎來到聽力練習第44期--為大家每日提供一點地道英語學習素材,助力英語學習。
  • 黑色期貨市場表現強勢 期螺強勢反彈
    黑色期貨市場表現強勢 期螺強勢反彈 來源:我的鋼鐵網 • 2020-12-11 15:15:16 12月10日,國內鋼材指數(Myspic)綜合指數報156.39
  • 雜論 || Emergence, 細胞自動機與本體論疑難
    在二十世紀早期,馮·諾伊曼在研究可以自我複製的系統的時候,提出了細胞自動機(CellularAutomata)的概念。細胞自動機是有限狀態機(Finite-stateMachine)的一種。第四類細胞自動機非常有趣,因為它證實了僅僅是最簡單的規則所指定的一種細胞自動機也可以自發地演化出特殊的秩序。Emergence在最基礎的數理層面存在,而且它的諸多現象也是無法被還原為更基礎的理論的。
  • 國際自動機工程師學會在滬籤署戰略發展協議
    國際自動機工程師學會在滬籤署戰略發展協議中國經濟周刊-經濟網訊 (見習記者 宋傑)中國經濟周刊-經濟網記者今日從國際自動機工程師學會(SAE International)獲悉,該協會正式與5家中國企事業單位籤訂了戰略合作發展協議,根據合作協議,今後每年12月將在上海舉行國際汽車電氣化和智能化高峰論壇