先簡單複習一下學習ac自動機所需要的字首知識。
#字首知識 1-trie樹
字典樹,也稱trie樹,字首樹,主要用於儲存大量的字串以及查詢操作。
對於trie樹,一般有兩個操作:
舉個例子,對於這樣幾個字串,我們看他們在trie樹中是如何儲存的:
這裡需要注意,字元是邊,而不是節點,但都是一一對應的
int son[n][26
],cnt[n]
,idx;
//cnt陣列記錄以當前節點為結尾的字串的數目,idx為節點編號
int n;
void
insert
(string& s)
cnt[p]++;
}int
query
(string &s)
return cnt[p]
;}
對於kmp演算法的介紹網上有很多優秀的部落格,這裡就不再贅述了。。。
**了解:**我們知道kmp演算法是解決單模式串的匹配問題的,而ac自動機是用來解決多模式串匹配問題的。
對於多模式串的儲存,我們就可以用到trie樹來儲存,在匹配過程中,一旦發生失配,我們應該如何處理呢?在kmp演算法中,我們對模式串構建了next陣列,在失配時通過next陣列來加速匹配過程,那在trie樹中,我們是不是也可以通過乙個陣列來維護字首和字尾的某些資訊呢?
定義:對於trie樹中當前某個節點i
,若fail[i]=j
表示trie樹中到j
為止的字串是到i
為止的字串的最長字尾。
有了這個fail陣列後,我們模擬乙個簡單的樣例,比如當前主串是uhershef
大家可以自己模仿樣例在紙上畫一下過程,在理解了這個過程之後,其實fail陣列也就不再那麼神秘了,當我們在乙個分支上走不下去了之後,我們不必頭鐵,可以換個方向繼續往下走,而fail陣列的作用就是這樣,當發生失配時,我們可以通過預處理出的fail陣列告訴我們其他分支的資訊(即滿足當前字串最長字尾的節點),然後繼續向後遍歷即可。
在trie樹建好之後,我們如何給這棵樹新增資訊即如何預處理出fail陣列,其實仔細觀察第一幅圖我們就可以看出來,我們可以利用前一層的資訊來更新下一層的節點資訊,那麼我們可以用bfs來一層一層地擴充套件。
**如下:
void
build()
while
(hh<=tt)}}
}
強烈建議大家畫個圖自己模擬一遍,絕對比直接對照**看有效!!
匹配的過程在第二張圖裡面已經提及到了,大致過程如下,從根節點開始匹配,如果匹配,繼續跳到下乙個節點,如果失配,則跳到fail指標,然後繼續匹配。
對於trie圖,我的個人理解是,利用fail指標來補充trie樹的資訊,使其成為乙個圖,然後在匹配過程中,我們無需考慮fail指標,直接令j = tr[j][t]
,這裡其實就包括了t+'a'
這個字元如果不存在時的情況,如果不存在,其實就等價於j = tr[fail[j]][t]
。
#include
using
namespace std;
const
int n =
1e4+
100, l =
55, m =
1e6+
100;
char str[m]
,s[l]
;int tr[n*l][26
], cnt[n*l]
,idx;
int fail[n*l]
,q[n*l]
;int t,n;
//字典樹建樹過程
void
insert
(char s)
cnt[p]++;
}//寬搜預處理出fail陣列以及trie子圖
void
build()
while
(hh<=tt)}}
}int
main()
build()
;scanf
("%s"
,str)
;int ans =0;
for(
int i =
0,j =
0; str[i]
; i++)}
printf
("%d\n"
,ans);}
return0;
}
AC自動機 學習筆記
是一種數學模型,大概就是由一堆狀態和狀態轉移規則等東西構成,能與外界交換資訊,並改變動作。這個是理論上的東西,了解就行,對ac自動機的理解沒有大影響。通俗的講就是在trie上做kmp,處理多模式串匹配問題。trie 的每個結點就是乙個狀態,根結點是初始狀態。ac自動機的行為被定義為一下3個函式 1....
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自動機的理論,思想。首先我們必須要明確乙...