淺談Aho-Corasick automaton(AC自動機)

Aho-Corasick automaton是什么?

要學會AC自動機,我們必須知道什么是Trie,也就是字典樹。Trie樹,又稱單詞查找樹或鍵樹,是一種樹形結構,是一種哈希樹的變種。典型應用是用于統計和排序大量的字符串(但不僅限于字符串),所以經常被搜索引擎系統用于文本詞頻統計。

首先我們要知道trie,而且要知道KMP,這樣就可以學AC自動機了!

其實AC自動機就是trie和KMP的結合體。主要構建trie后使用KMP的主導思想構建fail邊,每次匹配與KMP相似。

下面我們看看如何構造fail邊。

fail邊就是類似KMP中的next數組,在失配的時候能夠指向的地方。
這里寫圖片描述

這就是一顆trie樹,那么我們應該怎么去連fail邊呢?

首先我們知道root的fail邊是連向自己的,而且所有與root直接相連的點fail都指向root。
這里寫圖片描述
然后每個點,看看自己父親的fail邊指向的位置的點是否有一個與它長的一樣的兒子,如果有,那么連上,否則繼續找fail邊,直到root為止(注意這個過程我們用bfs實現)。所以最終連完的fail邊就是這樣:
這里寫圖片描述
這樣我們只需要每一位去匹配就好了。

有人問,怎么匹配:

舉個栗子:
用上面的圖:
這里寫圖片描述
假設原串是:ahershe,這棵trie上有his,her,he,she。
我們從root開始,先查找root點有沒有當前字母的兒子a,有那么指針x指到h點上,這樣一直匹配;如果沒有,那么就直接跳到當前點的fail邊上,這樣保證前面匹配的全都是相同的,直到有這樣的兒子或者已經到了root并且沒有這樣的兒子為止。
注意每跳一個點就必須從當前點遍歷一遍它的fail邊直到root的邊集,就是說沿著fail邊跳一直到root為止,這是為了避免當前點沒有被標記,但是在它fail邊到達root的路徑上有被標記的點。

Exanple

【GDOI2013模擬4】貼瓷磚

Description

A鎮的主街是由N個小寫字母構成,鎮長準備在上面貼瓷磚,瓷磚一共有M種,第i種上面有Li個小寫字母,瓷磚不能旋轉也不能被分割開來,瓷磚只能貼在跟它身上的字母完全一樣的地方,允許瓷磚重疊,并且同一種瓷磚的數量是無窮的。
問街道有多少字母(地方)不能被瓷磚覆蓋。

Input

第一行輸入街道長度N(1<=N<=300,000)。
第二行輸入N個英文小寫字母描述街道的情況。
第三行輸入M(1<=M<=5000),表示瓷磚的種類。
接下來M行,每行描述一種瓷磚,長度為Li(1<=Li<=5000),全部由小寫字母構成。

Output

輸出有多少個地方不能被瓷磚覆蓋。

Sample Input

輸入1:

6

abcbab

2

cb

cbab

輸入2:

4

abab

2

bac

baba

輸入3:

6

abcabc

2

abca

cab

Sample Output

輸出1:

2

輸出2:

4

輸出3:

1

Data Constraint

N(1<=N<=300,000)

Solution

我們把原字符串每一位都進行匹配,然后首先預處理出trie中每一個點對應所有fail邊中最大的長度,然后匹配的時候記錄下每一位中能夠覆蓋到的最大長度,最后用線段樹維護(當然你可以直接用差分約束)。

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#define mo 1000010
using namespace std;
struct Moon{int fail,num,maxl;}point[4000010];
int son[4000010][27];
int lengt_max[300010],length[300010];
char s[300010],ch[300010];
int len,n,root,sz; 
int d[mo];
int f[300010*4],tag[300010*4];
void make_trie(char s1[300010],int len1,int t,int x,int id)
{if(t>len1) {point[x].num=id;point[x].maxl=length[id];return;}   if(!son[x][s1[t]-96]){son[x][s1[t]-96]=++sz;++son[x][0];make_trie(s1,len1,t+1,sz,id);   }else make_trie(s1,len1,t+1,son[x][s1[t]-96],id);
}
void build_fail()
{int i,x,k,head=0,tail=0;for (i=1;i<=26&&tail<son[root][0];++i)if(son[root][i]) {d[++tail]=son[root][i];point[son[root][i]].fail=root;}while(head!=tail){head=head%mo+1;x=d[head];if(!son[x][0]) continue;for (i=1;i<=26;++i)if(son[x][i]){tail=tail%mo+1;d[tail]=son[x][i];k=point[x].fail;while(k!=root){if(son[k][i]) break;k=point[k].fail;if(k==root&&!son[k][i]) break;}if(son[k][i]) point[son[x][i]].fail=son[k][i];else point[son[x][i]].fail=root;point[son[x][i]].maxl=max(point[son[x][i]].maxl,point[point[son[x][i]].fail].maxl);}}
}
void Check()
{int x=root,k;for (int i=1;i<=len;){if(son[x][s[i]-96]) {x=son[x][s[i]-96];  lengt_max[i]=max(lengt_max[i],point[x].maxl);++i;}   else x=point[x].fail;if(x==root&&!son[x][s[i]-96]) ++i;}
} 
void change(int v,int l,int r,int x,int y)
{if(l==x&&r==y){tag[v]=1;f[v]=r-l+1; return;}int mid=(l+r)/2;if(tag[v]){tag[v*2]=1,f[v*2]=mid-l+1;tag[v*2+1]=1,f[v*2+1]=r-mid;tag[v]=0;}if(y<=mid) change(v*2,l,mid,x,y);else if(x>mid) change(v*2+1,mid+1,r,x,y);else change(v*2,l,mid,x,mid),change(v*2+1,mid+1,r,mid+1,y);f[v]=f[v*2]+f[v*2+1];
}
int main()
{scanf("%d",&len);scanf("%s",s+1);scanf("%d",&n);int i,j;root=sz=point[1].fail=1;for (i=1;i<=n;++i){scanf("%s",ch+1);length[i]=strlen(ch+1);make_trie(ch,length[i],1,root,i);}build_fail();Check();for (i=1;i<=len;++i) if(lengt_max[i]) change(1,1,len,i-lengt_max[i]+1,i);printf("%d\n",len-f[1]);
}

轉載于:https://www.cnblogs.com/Chandery/p/11332808.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248263.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248263.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248263.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

javaScript第七天(2)

javaScript基礎 ? 對象其他部分 [理解] 自定義構造函數創建對象[掌握] //繼續簡化 自定義構造函數 function People(uName, uAge) {this.uName uName;this.uAge uAge; } // 如何通過自定義構造函數創建對象? var zs new People(張三, 20); console.log(zs);注意事項: 自定…

數據挖掘、機器學習書籍推薦!!

強烈推薦&#xff1a;《機器學習》 (西瓜書) 入門讀物&#xff1a; 《深入淺出數據分析》 這書挺簡單的&#xff0c;基本的內容都涉及了&#xff0c;說得也比較清楚&#xff0c;最后談到了R是大加分。難易程度&#xff1a;非常易。 《啤酒與尿布》 通過案例來說事情&#xff0c…

樓蘭圖騰(權值線段樹)

在完成了分配任務之后&#xff0c;西部314來到了樓蘭古城的西部。 相傳很久以前這片土地上(比樓蘭古城還早)生活著兩個部落&#xff0c;一個部落崇拜尖刀(‘V’)&#xff0c;一個部落崇拜鐵鍬(‘∧’)&#xff0c;他們分別用V和∧的形狀來代表各自部落的圖騰。 西部314在樓蘭古…

js(Dom+Bom)第一天(1)

JavaScript-DOM&#xff08;BOM&#xff09;操作 核心知識 獲取頁面元素事件設置樣式 學習目標 能夠使用id名,標簽名等方式獲取頁面中元素能夠給標簽注冊點擊事件,并實現對應效果能夠給標簽通過js方式設置樣式 JavaScript組成 ECMASCRIPT (基礎語法) DOM&#xff08;文檔對…

[HZNOI #koishi] Magic

[HZNOI #514] Magic 題意 給定一個 \(n\) 個點 \(m\) 條邊的有向圖, 每個點有兩個權值 \(a_i\) 和 \(b_i\), 可以以 \(b_i\) 的花費把第 \(i\) 個點的 \(a_i\) 變成 \(0\). 最后每個點 \(i\) 產生的花費為所有從 \(i\) 出發能通過一條有向邊直接到達的點 \(j\) 的 \(a_j\) 的 \…

同步與異步

同步&#xff1a; 做完一件事&#xff0c;再做另一件 煮好水&#xff0c;再拆泡面包裝 異步&#xff1a; 可以同時做好幾個任務 燒水&#xff0c;打開火之后&#xff0c;先去拆泡面包裝&#xff0c;等水開了&#xff0c;再停下拆包裝&#xff0c;去關掉火。。。。。 轉載于:htt…

js(Dom+Bom)第一天(2)

webAPI 00-復習 內置對象中的方法 01-JavaScript組成 知識點-ECMASCRIPT 重點回顧 存儲容器 變量數組對象 邏輯語法 分支語句循環語句switch語句 知識點-BOM 概念 Browser Object Model (瀏覽器器對象模型) 操作瀏覽器將瀏覽器看做是一個對象.作用 通過js操作瀏覽器中相…

mysql 主主復制的配置流程

1、先關閉B&#xff0c;把A的數據導出來&#xff0c;mysqldump -hlocalhost -uroot -p123456 --database ibprpu >ibprpu.sql2、關閉A&#xff0c;啟動B&#xff0c;進入mysql建立一個新的數據庫 create database ibprpu3、導入數據庫 mysql -hlocalhost -uroot -p123456 &l…

華為架構師8年經驗談:從單體架構到微服務的服務化演進之路

本次分享的技術大綱如下&#xff1a; 傳統應用開發面臨的挑戰服務化實踐服務化不是銀彈服務化架構的演進方向一 、傳統應用開發面臨的挑戰 挑戰1-- 研發成本高 主要體現在如下幾個方面&#xff1a; 代碼重復率高在實際項目分工時&#xff0c;開發都是各自負責幾個功能&#xff…

輪播圖制作(1)

輪播圖制作 <body><div><img src"img/1.jpg" class"imgs" alt""><a href"#" class"left"><</a> //此處的箭頭也可以用圖標做出來<a href"#" class"right">>…

StringUtils工具類的常用方法

StringUtils 方法的操作對象是 java.lang.String 類型的對象&#xff0c;是 JDK 提供的 String 類型操作方法的補充&#xff0c;并且是 null 安全的(即如果輸入參數 String 為 null 則不會拋出 NullPointerException &#xff0c;而是做了相應處理&#xff0c;例如&#xff0c…

struts2+extjs文件上傳完整實現(攻克了上傳中的各種問題)

版權聲明&#xff1a;本文為博主原創文章。未經博主同意不得轉載。 https://blog.csdn.net/shanhuhau/article/details/28617999 首先須要引入上傳控件 <script type"text/javascript" src"<%basePath%>/js/ext/examples/ux/fileuploadfield/FileUploa…

放大鏡制作(1)

放大鏡制作 <div class"box" id"box"><!--左側的盒子--><div class"small"><!--圖片--><img src"images/big.jpg" width"350" class"aaa" alt""/><!--黃色小盒子--&…

.NET Framework 2.0 組件和非托管代碼與交互操作詳解(轉)

.NET Framework 將促進與 COM 組件、COM 服務、外部類型庫和許多操作系統服務的交互操作。在托管和非托管對象模型之間&#xff0c;數據類型、方法簽名和錯誤處理機制都存在差異。為了簡化 .NET Framework 組件和非托管代碼之間的互用并便于進行移植&#xff0c;公共語言運行時…

git 刪除遠程分支和本地分支

刪除遠程分支和本地分支 https://www.cnblogs.com/luosongchao/p/3408365.html 將遠程git倉庫里的指定分支拉取到本地&#xff08;本地不存在的分支&#xff09; https://www.cnblogs.com/hamsterPP/p/6810831.html 轉載于:https://www.cnblogs.com/mafeng/p/10619419.html

從零開始實現ASP.NET Core MVC的插件式開發(四) - 插件安裝

標題&#xff1a;從零開始實現ASP.NET Core MVC的插件式開發(四) - 插件安裝 作者&#xff1a;Lamond Lu 地址&#xff1a;https://www.cnblogs.com/lwqlun/p/11343141.html 源代碼&#xff1a;https://github.com/lamondlu/Mystique 前情回顧 從零開始實現ASP.NET Core MVC的插…

立體導航翻轉案例

<div class"box"><!-- 立方體 --><ul><li><img src"img1/1.jpg" alt""></li><li><img src"img1/2.jpg" alt""></li><li><img src"img1/3.jpg" a…

Uncontrolled memory mapping in camera driver (CVE-2013-2595)

版權聲明&#xff1a;本文為博主原創文章&#xff0c;未經博主同意不得轉載。https://blog.csdn.net/hu3167343/article/details/34434235 /* 本文章由 莫灰灰 編寫&#xff0c;轉載請注明出處。 作者&#xff1a;莫灰灰 郵箱&#xff1a; minzhenfei163.com */ 1漏洞描寫…

表格隔行變色

<body><table border"0" align"center" cellspacing"1" cellpadding"0"><caption>恭喜發財</caption><thead><tr><th>代碼</th><th>名稱</th><th>最新公布凈值<…

啟動Cognos時報0106錯誤

1. 問題描述 啟動Cognos失敗&#xff0c;報錯代碼為0106。 2. 問題分析 是jdk版本不兼容。 3. 解決方案 方案一&#xff1a;更換jdk1.6&#xff0c;可以使用免安裝版&#xff0c;不需要卸載原有的jdk將java_home的路徑替換成jdk1.6的路徑。 方案二&#xff1a;使用Cognos自帶jd…