AC自动机入门经典题目(两种表达方式)

Keywords Search

指针方式:

  1 /* Keywords Search */
  2 # include <iostream>
  3 # include <stdio.h>
  4 # include <string.h>
  5 # include <string>
  6 # include <cstdlib>
  7 # include <ctime>
  8 # include <cmath>
  9 # include <cctype>
 10 # include <vector>
 11 # include <deque>
 12 # include <queue>
 13 # include <stack>
 14 # include <climits>
 15 # include <bitset>
 16 # include <set>
 17 # include <map>
 18 using namespace std;
 19 
 20 # define N 1001000
 21 # define INF 0x3f3f3f3f
 22 # define lowbit(x)(x&(-x))
 23 
 24 struct node
 25 {
 26     int cnt;
 27     node *next[26];
 28     node *fail;
 29     node(){
 30             cnt=0;
 31             fail=NULL;
 32             memset(next, NULL, sizeof(next));
 33     }
 34 };
 35 node *root;
 36 char s[55], str[N];
 37 int n;
 38 
 39 void init()
 40 {
 41     root = new node;
 42 }
 43 
 44 void _Insert(char *ss)
 45 {
 46     int len = strlen(ss);
 47     node *p=root;
 48     for(int i=0; i<len; i++ )
 49     {
 50         int t=ss[i]-'a';
 51         if( p->next[t]==NULL )
 52             p->next[t]=new node;
 53         p=p->next[t];
 54     }
 55    p->cnt++;
 56 }
 57 
 58 void Build_the_fail()
 59 {
 60     root -> fail = NULL;
 61     //node *p=root;
 62     queue<node*>q;
 63     q.push(root);
 64 
 65     while( !q.empty() )
 66     {
 67         node *cur=q.front();
 68         q.pop();
 69 
 70         for(int i=0; i<26; i++ )
 71         {
 72             if( cur->next[i]!=NULL )
 73             {
 74                 if( cur==root )
 75                     cur->next[i]->fail = root;
 76                 else
 77                 {
 78                     node *p=cur->fail;
 79                     while( p!=NULL )
 80                     {
 81                         if( p->next[i]!=NULL )
 82                         {
 83                             cur->next[i]->fail = p->next[i];
 84                             break;
 85                         }
 86 
 87                         else
 88                         {
 89                             p = p -> fail;
 90                         }
 91                     }
 92                     if( p==NULL )
 93                         cur->next[i]->fail = root;
 94                 }
 95                 q.push(cur->next[i]);
 96             }
 97         }
 98     }
 99 }
100 
101 int query(char *str)
102 {
103     node *cur=root;
104     int pos;
105     int cont=0;
106     int len=strlen(str);
107     for(int i=0; i<len; i++ )
108     {
109         pos=str[i]-'a';
110         while( cur->next[pos]==NULL && cur!=root )
111         {
112             cur = cur->fail;
113         }
114         cur = cur->next[pos];
115         if( cur==NULL )
116             cur = root;
117         node *temp=cur;
118         while( temp!=root )
119         {
120             if( temp->cnt!=-1 )
121             {
122                 cont += temp-> cnt;
123                 temp -> cnt = -1;
124             }
125             temp = temp -> fail;
126         }
127     }
128     return cont;
129 }
130 
131 int main()
132 {
133     int t;
134     scanf("%d", &t);
135     while( t-- )
136     {
137         init();
138         scanf("%d", &n);
139         for(int i=0; i<n; i++ )
140         {
141             scanf("%s", s);
142             _Insert(s);
143         }
144         Build_the_fail();
145         scanf("%s", str);
146         printf("%d
", query(str));
147     }
148     return 0;
149 }
View Code

 数组方式:

  1 /* */
  2 # include <iostream>
  3 # include <algorithm>
  4 # include <utility>
  5 # include <memory>
  6 # include <deque>
  7 # include <queue>
  8 # include <stack>
  9 # include <map>
 10 # include <set>
 11 # include <list>
 12 # include <vector>
 13 # include <cassert>
 14 # include <functional>
 15 # include <bitset>
 16 # include <cmath>
 17 # include <cstdlib>
 18 # include <climits>
 19 # include <cstring>
 20 # include <string>
 21 using namespace std;
 22 typedef long long ll;
 23 
 24 # define mem(a,b)(a,b,sizeof(a))
 25 # define lowbit(x)(x&(-x))
 26 # define lcm(a,b)(a*b/__gcd(a,b))
 27 const ll mod=1e9+7;
 28 const int maxn=500010;
 29 const double pi=acos(-1.0);
 30 
 31 struct ac_auto
 32 {
 33     int Next[maxn][26], Fail[maxn], End[maxn];//Next[now][buf[i]-'a'] 是now节点存着buf[i]字符的子节点的编号
 34     int L, root;//注意这是全局变量,L是编号,root是根节点
 35 
 36 
 37     int newNode(){
 38         for(int i=0; i<26; i++ )//26叉树
 39             Next[L][i] = -1;
 40         End[L++] = 0;
 41         return L-1;//返回节点编号
 42     }
 43 
 44     void Initial(){
 45         L=0;
 46         root = newNode();
 47     }
 48 
 49     void Insert( char buf[] )
 50     {
 51         int len=strlen(buf);
 52         int now = root;
 53         for(int i=0; i<len; i++ )
 54         {
 55             if( Next[now][buf[i]-'a'] == -1 )
 56                 Next[now][buf[i]-'a'] = newNode();//若子节点没有buf[i],则插入buf[i]
 57             now = Next[now][buf[i]-'a'];//now是当前节点编号
 58         }
 59         End[now]++;//作为结束字符的编号+1,计算单词出现的次数
 60     }
 61 
 62     void Build_the_fail()
 63     {
 64         queue<int>ans;
 65         Fail[root] = root;//根节点的失败指针指向自己
 66 
 67         for(int i=0; i<26; i++ )
 68         {
 69             if( Next[root][i]==-1 )
 70                 Next[root][i] = root;
 71             else
 72             {
 73                 Fail[Next[root][i]] = root;//根节点的子节点的失败指针指向根节点
 74                 ans.push(Next[root][i]);
 75             }
 76         }
 77 
 78         while( !ans.empty() )
 79         {
 80             int now = ans.front();
 81             ans.pop();
 82 
 83             for(int i=0; i<26; i++)
 84             {
 85                 if( Next[now][i]==-1 )
 86                     Next[now][i] = Next[Fail[now]][i];//若buf[i]没有插入字典树,则将令其等于其父节点的失败指针指向的节点的子节点buf[i]字符所在的节点
 87                 else
 88                 {
 89                     Fail[Next[now][i]] = Next[Fail[now]][i];//若buf[i]已经插入,其失败指针就指向其父节点的失败指针指向的节点的子节点buf[i]所在的节点
 90                     ans.push(Next[now][i]);//
 91                 }
 92             }
 93         }
 94     }
 95 
 96     int Query( char buf[] )
 97     {
 98         int now = root;//从根节点开始找,now初始化为root
 99         int res = 0;//结果
100         int len = strlen(buf);
101 
102         for(int i=0; i<len; i++ )
103         {
104             now = Next[now][buf[i]-'a'];//当前节点的编号
105             int temp = now;
106             while( temp!=root )
107             {
108                 res += End[temp];//只有找到单词最后一个字符所在位置End[temp]才会>0,否则为0,所以可以直接加
109                 End[temp] = 0;//加完后置为0
110                 temp = Fail[temp];//拓展到失败指针指向的位置,继续找
111             }
112         }
113         return res;
114     }
115 }AC;
116 
117 const int MAXN = 1000010;
118 int T, n;
119 char buf[MAXN];
120 
121 int main()
122 {
123     ios::sync_with_stdio(false);
124     cin>>T;
125     while( T-- )
126     {
127         cin>>n;
128         AC.Initial();
129         for(int i=0; i<n; i++ )
130         {
131             cin>>buf;
132             AC.Insert(buf);
133         }
134         AC.Build_the_fail();
135         cin>>buf;
136         cout<<AC.Query(buf)<<endl;
137     }
138     return 0;
139 }
View Code
原文地址:https://www.cnblogs.com/wsy107316/p/11455270.html