日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AC automation 模板

發布時間:2023/12/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AC automation 模板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1 /* 2 1.對n個字符串構造tire樹 insertWord(node *root, char *word); 3 2.bfs構造fail指針 makeFail(node *root); 4 3.基于以上兩點的查詢 query(node *root, char *str); 5 */ 6 #include <stdio.h> 7 #include <string.h> 8 #include <queue> 9 using namespace std; 10 const int N1 = 50 + 10; 11 const int N2 = 1000000 + 10; 12 char key[N1]; 13 char desc[N2]; 14 struct node 15 { 16 node *next[26]; 17 int cnt; 18 node *fail; 19 node(){for(int i=0; i<26; ++i) next[i] = NULL; fail = NULL; cnt = 0;} 20 }; 21 void insertWord(node *root)//構造trie樹 22 { 23 node *cur = root; 24 int n = strlen(key); 25 for(int i=0; i<n; ++i) 26 { 27 int index = key[i] - 'a'; 28 if(cur->next[index] != NULL) 29 cur = cur->next[index]; 30 else 31 { 32 cur->next[index] = new node(); 33 cur = cur->next[index]; 34 } 35 } 36 cur->cnt++; 37 } 38 void makeFail(node *root)//構造fail指針 39 { 40 queue<node*> q; 41 q.push(root); 42 node *cur; 43 while(!q.empty()) 44 { 45 cur = q.front(); 46 q.pop(); 47 for(int i=0; i<26; ++i) 48 { 49 if(cur->next[i] != NULL) 50 { 51 if(cur == root)//與root相連的結點,即第二層的結點的fail指針都是root 52 cur->next[i]->fail = root; 53 else 54 { 55 node *tmp = cur; 56 while(tmp->fail != NULL)// why while? 57 { 58 if(tmp->fail->next[i] != NULL) 59 { 60 cur->next[i]->fail = tmp->fail->next[i]; 61 break; 62 } 63 tmp = tmp->fail; 64 } 65 if(tmp->fail == NULL) 66 cur->next[i]->fail = root; 67 } 68 q.push(cur->next[i]); 69 } 70 } 71 } 72 } 73 int query(node *root)//查詢 74 { 75 node *cur = root; 76 node *tmp = NULL; 77 int i=0,cnt=0; 78 while(desc[i]) 79 { 80 int index = desc[i] - 'a'; 81 while(cur!=root && cur->next[index] == NULL) 82 cur = cur->fail; 83 if(cur->next[index] != NULL) 84 { 85 cur = cur->next[index]; 86 tmp = cur; 87 while(tmp != root && tmp->cnt!=0) 88 { 89 cnt += tmp->cnt; 90 tmp->cnt = 0; 91 tmp = tmp->fail; 92 } 93 } 94 i++; 95 } 96 return cnt; 97 } 98 int main() 99 { 100 int t,n; 101 scanf("%d",&t); 102 while(t--) 103 { 104 node *root = new node(); 105 scanf("%d",&n); 106 for(int i=0; i<n; ++i) 107 { 108 scanf("%s",key); 109 insertWord(root); 110 } 111 makeFail(root); 112 scanf("%s",desc); 113 int ans = query(root); 114 printf("%d\n",ans); 115 } 116 return 0; 117 } View Code 1 //多串匹配,n個模式字符串構成AC自動機,然后目標串去匹配,看目標串中有多少個模式串 2 #include <stdio.h> 3 #include <string.h> 4 #include <queue> 5 using namespace std; 6 /* 7 根結點的fail指針為NULL,根結點的直接子結點的fail指針為root,很明顯,當一個字符都不匹配時,從根結點再開始匹配 8 每個結點的fail指針都是由它父結點的fail指針決定的。 9 */ 10 const int N = 1000000 + 10; 11 struct node 12 { 13 node *next[26],*fail; 14 int cnt; 15 node(){for(int i=0; i<26; ++i) next[i] = NULL; fail = NULL; cnt = 0;} 16 }; 17 void insertWord(node *root, char *word) 18 { 19 node *cur = root; 20 int i = 0; 21 while(word[i]) 22 { 23 int index = word[i] - 'a'; 24 if(cur->next[index] == NULL) 25 cur->next[index] = new node(); 26 cur = cur->next[index]; 27 ++i; 28 } 29 cur->cnt ++; 30 } 31 char str[N]; 32 void makeFail(node *root) 33 { 34 node *cur,*tmp; 35 queue<node*> q; 36 q.push(root); 37 while(!q.empty()) 38 { 39 cur = q.front(); 40 q.pop(); 41 for(int i=0; i<26; ++i) 42 { 43 if(cur->next[i] != NULL) 44 { 45 q.push(cur->next[i]); 46 if(cur == root)//如果當前結點是root,那么它的直接孩子結點的fail指針指向root 47 cur->next[i]->fail = root; 48 else 49 { 50 tmp = cur; 51 while(tmp->fail != NULL)//because root->fail == NULL,如果到了這個地步,說明當前字符串沒有后綴 52 { 53 if(tmp->fail->next[i] != NULL) 54 { 55 cur->next[i]->fail = tmp->fail->next[i]; 56 break; 57 } 58 tmp = tmp->fail; 59 } 60 if(tmp->fail == NULL) 61 cur->next[i]->fail = root; 62 } 63 } 64 } 65 } 66 } 67 68 // how to query??? 69 int query(node *root, char *str) 70 { 71 node *cur = root; 72 node *tmp = NULL; 73 int i = 0, cnt = 0; 74 while(str[i]) 75 { 76 int index = str[i] - 'a'; 77 while(cur!=root && cur->next[index]==NULL)//如果失配,那么直接跳到fail指針處去匹配 78 cur = cur->fail; 79 if(cur->next[index] != NULL) 80 { 81 cur = cur->next[index];//如果當前字符匹配成功,則跳到那個字符, 82 tmp = cur; 83 //這就是為什么Ac自動機效率高的緣故,根據fail指針,跳到當前字符串的最長后綴去 84 //如果tmp->cnt != 0 說明存在該最長后綴形成的字符串 85 while(tmp->cnt!=0) 86 { 87 cnt += tmp->cnt; 88 tmp->cnt = 0; 89 tmp = tmp->fail; 90 } 91 } 92 ++i; 93 } 94 return cnt; 95 } 96 int main() 97 { 98 int t,n; 99 scanf("%d",&t); 100 char word[55]; 101 while(t--) 102 { 103 node *root = new node(); 104 scanf("%d",&n); 105 for(int i=0; i<n; ++i) 106 { 107 scanf("%s",word); 108 insertWord(root, word); 109 } 110 scanf("%s",str); 111 makeFail(root); 112 int ans = query(root, str); 113 printf("%d\n",ans); 114 } 115 return 0;

給定n個模式串,長度均不超過m,和一個目標串(長度為L),問目標串中包含多少個模式串(可重疊
的)。
暴力算法是一個個模式串去與目標串匹配,時間復雜度是O(n*m*L)
有更好的算法是AC自動機,時間復雜度是O(n)(這個怎么算來著??)

AC自動機分為兩步,1.構建trie樹。2.構建fail指針。正是這個fail指針將時間復雜度給大大縮小了

fail指針是匹配失敗時,該跳到那個結點去重新匹配
fail指針是指向當前字符串的最長后綴,比如she的fail指針應該指向he或e或root(即指向存在的最長后
綴)
所以當前結點的fail指針由父結點的fail指針所決定

?

?學習資料:http://www.cppblog.com/menjitianya/archive/2014/07/10/207604.html

轉載于:https://www.cnblogs.com/justPassBy/p/3964004.html

總結

以上是生活随笔為你收集整理的AC automation 模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。