AC自動機詳解 入門模板 HDU 2222

2021-06-01 18:57:50 字數 4370 閱讀 8145

第一次寫ac自動機,發現也不是太難理解,可能自己以前看過kmp&trie而且理解的比較透徹吧,看自動機沒有太大的困難,因為它也是利用了kmp的思想,理解了kmp,再看自動機就不難了:)

轉一下這個blog的描述先,感覺看起來比較好理解,可是他的**就不敢恭維。。。有改動)

補充一句:自動機的複雜度是o(m+n+z),其中z為主串中模式串的總個數,適合多模式串匹配。

首先簡要介紹一下ac自動機:aho-corasick automation,該演算法在2023年產生於貝爾實驗室,是著名的多模匹配演算法之一。乙個常見的例子就是給出n個單詞,再給出一段包含m個字元的文章,讓你找出有多少個單詞在文章裡出現過。要搞懂ac自動機,先得有模式樹(字典樹)trie和kmp模式匹配演算法的基礎知識。ac自動機演算法分為3步:構造一棵trie樹,構造失敗指標和模式匹配過程。

如果你對kmp演算法和了解的話,應該知道kmp演算法中的next函式(shift函式或者fail函式)是幹什麼用的。kmp中我們用兩個指標i和j分別表示,a[i-j+ 1..i]與b[1..j]完全相等。也就是說,i是不斷增加的,隨著i的增加j相應地變化,且j滿足以a[i]結尾的長度為j的字串正好匹配b串的前 j個字元,當a[i+1]≠b[j+1],kmp的策略是調整j的位置(減小j值)使得a[i-j+1..i]與b[1..j]保持匹配且新的b[j+1]恰好與a[i+1]匹配,而next函式恰恰記錄了這個j應該調整到的位置。同樣ac自動機的失敗指標具有同樣的功能,也就是說當我們的模式串在tire上進行匹配時,如果與當前節點的關鍵字不能繼續匹配的時候,就應該去當前節點的失敗指標所指向的節點繼續進行匹配。

看下面這個例子:給定5個單詞:say she shr he her,然後給定乙個字串yasherhs。問一共有多少單詞在這個字串中出現過。我們先規定一下ac自動機所需要的一些資料結構,方便接下去的程式設計。

const int kind = 26;

struct node ;

};char str[55];//輸入的單詞

char ss[m];//輸入的主串

queueqq;//佇列構造失敗指標

有了這些資料結構之後,就可以開始程式設計了:

首先,將這5個單詞構造成一棵trie,如圖-1所示。

//建trie樹

void buildtree (node *root)

p = p->next[id];

i++;

}(p->cnt)++;

}

在構造完這棵

trie

之後,接下去的工作就是構造下失敗指標。構造失敗指標的過程概括起來就一句話:設這個節點上的字母為

c,沿著他父親的失敗指標走,直到走到乙個節點,他的兒子中也有字母為

c的節點。然後把當前節點的失敗指標指向那個字母也為

c的兒子。如果一直走到了

root

都沒找到,那就把失敗指標指向

root

。具體操作起來只需要:先把

root

加入佇列

(root

的失敗指標指向自己或者

null)

,這以後我們每處理乙個點,就把它的所有兒子加入佇列,隊列為空。

//bfs求失敗指標

void bfs(node *root)

if (!p) tmp->next[i]->fail = root;

else tmp->next[i]->fail = p->next[i];

qq.push(tmp->next[i]);}}

}}

從**觀察下構造失敗指標的流程:對照圖-2來看,首先root的fail指標指向null,然後root入隊,進入迴圈。第1次迴圈的時候,我們需要處理2個節點:root->next[『h』-『a』](節點h) 和 root->next[『s』-『a』](節點s)。把這2個節點的失敗指標指向root,並且先後進入佇列,失敗指標的指向對應圖-2中的(1),(2)兩條虛線;第2次進入迴圈後,從佇列中先彈出h,接下來p指向h節點的fail指標指向的節點,也就是root;進入第13行的迴圈後,p=p->fail也就是p=null,這時退出迴圈,並把節點e的fail指標指向root,對應圖-2中的(3),然後節點e進入佇列;第3次迴圈時,彈出的第乙個節點a的操作與上一步操作的節點e相同,把a的fail指標指向root,對應圖-2中的(4),併入隊;第4次進入迴圈時,彈出節點h(圖中左邊那個),這時操作略有不同。在程式執行到14行時,由於p->next[i]!=null(root有h這個兒子節點,圖中右邊那個),這樣便把左邊那個h節點的失敗指標指向右邊那個root的兒子節點h,對應圖-2中的(5),然後h入隊。以此類推:在迴圈結束後,所有的失敗指標就是圖-2中的這種形式。

最後,我們便可以在ac自動機上查詢模式串中出現過哪些單詞了。匹配過程分兩種情況:(1)當前字元匹配,表示從當前節點沿著樹邊有一條路徑可以到達目標字元,此時只需沿該路徑走向下乙個節點繼續匹配即可,目標字串指標移向下個字元繼續匹配;(2)當前字元不匹配,則去當前節點失敗指標所指向的字元繼續匹配,匹配過程隨著指標指向root結束。重複這2個過程中的任意乙個,直到模式串走到結尾為止。

//ac自動機主程式

int ac_run(node *root)

p = p->next[id];

if (!p) p = root;

node *tmp = p;

while (tmp != root && tmp->cnt != -1)

i++;

}return ans;

}

對照圖-2,看一下模式匹配這個詳細的流程,其中模式串為yasherhs。對於i=0,1。trie中沒有對應的路徑,故不做任何操作;i=2,3,4時,指標p走到左下節點e。因為節點e的count資訊為1,所以cnt+1,並且講節點e的count值設定為-1,表示改單詞已經出現過了,防止重複計數,最後temp指向e節點的失敗指標所指向的節點繼續查詢,以此類推,最後temp指向root,退出while迴圈,這個過程中count增加了2。表示找到了2個單詞she和he。當i=5時,程式進入第5行,p指向其失敗指標的節點,也就是右邊那個e節點,隨後在第6行指向r節點,r節點的count值為1,從而count+1,迴圈直到temp指向root為止。最後i=6,7時,找不到任何匹配,匹配過程結束。

hdu 2222題可以作為ac自動機的模板題

貼上**

#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std;

#define ll long long

#define min int_min

#define max int_max

#define pi acos(-1.0)

#define fre freopen("input.txt","r",stdin)

#define ff freopen("output.txt","w",stdout)

#define n 10005

#define m 1000005

const int kind = 26;

struct node ;

};char str[55];//輸入的單詞

char ss[m];//輸入的模式串

queueqq;//佇列構造失敗指標

//建trie樹

void buildtree (node *root)

p = p->next[id];

i++;

}(p->cnt)++;

}//bfs求失敗指標

void bfs(node *root)

if (!p) tmp->next[i]->fail = root;

else tmp->next[i]->fail = p->next[i];

qq.push(tmp->next[i]);}}

}}//ac自動機主程式

int ac_run(node *root)

p = p->next[id];

if (!p) p = root;

node *tmp = p;

while (tmp != root && tmp->cnt != -1)

i++;

}return ans;

}int main ()

bfs(root);

scanf("%s",ss);

printf("%d\n",ac_run(root));

}return 0;

}

AC自動機演算法詳解(入門

首先簡要介紹一下ac自動機 aho corasick automation,該演算法在1975年產生於貝爾實驗室,是著名的多模匹配演算法之一。乙個常見的例子就是給出n個單詞,再給出一段包含m個字元的文章,讓你找出有多少個單詞在文章裡出現過。要搞懂ac自動機,先得有模式樹 字典樹 trie和kmp模式...

HDU2222 AC自動機 入門模板

hdu 222 keywords search ac 自動機入門模板題 調了一下午 因為輸入最後乙個字串打成了 d還有兩處取反符號打錯 wa了無數次 血淚史 以後要注意 ac自動機思路 這個演算法的目的 用幾個給定的模式串去在乙個串 t 中匹配 簡單概括實現方式 1.對所有的模式串建trie樹。2....

AC自動機模板

ac自動機模板 ac自動機模板 使用方法 1 init 初始化函式 2 insert str 插入字串函式 3 build 構建ac自動機 4 query str 返回出現的字串個數 使用需注意事項 1 注意輸入的字元的範圍,需對next和其二維大小及相關引數進行更改 2 注意next fail和e...