AC自動機詳解(附加可持久化AC自動機)

2022-05-19 02:38:06 字數 4587 閱讀 4217

ac自動機

ac自動機,說白了就是在

trie

樹上跑kmp

(其實個人感覺比

kmp容易理解)。是一種多匹配串,單個主串的匹配。概括來說,就是將多個匹配串構造乙個

trie

樹,對於每個

trie

樹的節點構造

nxt指標,最後把主串放在上面跑。

構造trie

和普通的

trie

樹構建一樣,沒有什麼區別

inline void insert(char *s)

isend[u]++;//

注意isend的具體處理根據題目而定

return

;}

構造nxt陣列其實這一部分是

ac自動機的核心,我們這樣構造:對於每個節點,它的nxt是,它父親的nxt的和它名字相同的兒子。如圖,

u的父親是

v,它父親的

nxt的

a這個兒子就是u的

還有一種情況,就是如果節點

u,它的沒有

a這個兒子,那麼它就要把

nxt[u]的a

這個兒子當成他的兒子。

如圖,因為u沒有

a的子節點,所以就連到

nxt[u]的a

子節點。

那麼這麼做的原因是什麼?我們來看一下這個圖:

如圖,這個

trie

樹中前7

個節點的

next

都已經構造完成了(箭頭表示他們的

nxt,1的

nxt是

0,沒有畫出來)

.現在要找8的

next

。按照「它的nxt是,它父親的nxt的和它名字相同的兒子」的原則,我們找到

8的父親,

7,發現7的

nxt,

5也沒有

b這個兒子,這時候我們需要找5的

next,2

,最終發現2有

b兒子,是4,將

8連到4。

但是注意,其實我們這乙個乙個找nxt是可以省略的。如果按著剛才「因為u沒有

a的子節點,所以就連到

nxt[u]的a

子節點。」樹就會變成這樣(黑線表示連邊,紅線表示

5因為沒有

b兒子,就把他的

nxt:2,的

b兒子:

4,當成自己的兒子,

7也同理,因為它沒有

a兒子,所以把他的

nxt的

a兒子:

2,當成自己的

a兒子。再來看

8,發現它的父親的

nxt,5,的

b兒子是

4,所以自己的

next就是4

了。這樣減少了剛才乙個乙個找

nxt的步驟。

inline void getnxt()}}

return

;}

查詢查詢的具體實現是根據題目而定,我就拿這道題舉個例子:給一大堆匹配串和乙個主串,求有多少個匹配串在主串上出現過。

這種題的做法就是現在構建

trie

樹的時候,把每個單詞的結尾都記錄一下:

isend[i]++

。最後跑一遍

ac自動機,到每乙個節點是

ans+=isend[i];isend=0;

這樣聽起來很簡單,那麼怎麼遍歷

ac自動機呢?

迴圈遍歷主串s,令

u表示當前點,每當主串

s到下一位時,

u=tree[u][s[i]-『a』]

(就是等於它的兒子)。然後對於每個

u,迴圈它的

nxt直到根。每到乙個點就

ans+=isend

。具體看**:

inline void

search()

k=nxt[k];

}u=tree[u][c];//

遍歷到它的兒子。

} printf(

"%d\n

",ans);

}

總結再來回顧一下

ac自動機的步驟:構建

trie

樹,構建

next

陣列,查詢。其中

next

有兩個原則:1、當這個節點沒有字元c這個兒子時,把自己的nextc這個兒子當做自己的兒子

2、自己兒子的nxt等於自己nxt的兒子

附上**:#include

#include 

#include

#include

#include

#include

#include

#include

#include

using

namespace

std;

#define maxn 100010

#define inf 10000009

#define mod 10000007

#define ll long long

#define in(a) a=read()

#define rep(i,k,n) for(int i=k;i<=n;i++)

#define drep(i,k,n) for(int i=k;i>=n;i--)

#define cl(a) memset(a,0,sizeof(a))inline

intread()

inline

void

out(int

x)int

t,n;

int total=1

;int nxt[1000010],tree[500010][26

];char

in[55

];int isend[1000010

];char t[1000010

];queue

q;int calc(char

c)inline

void insert(char *s)

isend[u]++;

return;}

inline

void getnxt()}}

return;}

inline

void

search()

k=nxt[k];

}u=tree[u][c];//遍歷

到它的兒子。

} printf(

"%d\n

",ans);

}int

main()

scanf("%s

",t);

getnxt();

search();

}return0;

}

附加:可持久化ac自動機如果你希望每當你查詢到乙個字串,然後要把它刪去時,就需要可持久化

ac自動機。其實和普通的

ac自動機很像,唯一區別是查詢的時候去掉了對於每乙個u遍歷

nxt直到根的步驟,然後讓每個

u都壓進棧,遇到

end就彈出棧裡面此字串長度的元素。

AC自動機詳解

最近真是太頹了,做了一堆板子題,現在對一些知識點順便來個總結記錄 大家應該都知道kmp和trie樹吧,不懂的可以看我部落格或到網上自己動手尋找資料。ac自動機是乙個很好的東西,這是因為它的名字很好它能夠在有多個模式串的時候進行全文匹配,這十分方便地擴充套件了kmp的功能,實際上它的思路與原理與kmp...

AC自動機詳解

首先,ac自動機,不是 自動accepted機,這是乙個多模字串匹配演算法,學習這個演算法,首先要熟悉kmp演算法這個單模字串匹配演算法,然後,我們知道有個高效的多模字串匹配演算法,叫字典樹,它處理的是一些單詞在乙個句子裡出現了幾次,但假如不是在乙個句子裡,而是在乙個字串裡呢?那它就顯得很弱了,所以...

AC自動機詳解

include include include include include include include include using namespace std typedef long long ll const int maxn 2 1e6 9 int trie maxn 26 字典樹 i...