AC automation 模板
生活随笔
收集整理的這篇文章主要介紹了
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 模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Sql Server 开窗函数Over(
- 下一篇: plsql 简单介绍