[hdu2222]Keywords Search(AC自动机)

题意:给定n个单词,一个字符串,问字符串中出现了多少个单词。

解题关键:AC自动机模板题,注意根据题意,匹配完成之后要置0.

注意char数组也可以用cin,

注意理解AC自动机,不可能在同一层 出现两个相同的前缀,不然会合并在一起的,所以一定会分层,所以可以依靠fail指针递归寻找。

AC自动机最重要的地方在于 用后缀来匹配前缀

复杂度:$O(NS + T)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=26;
 5 const int MAXN=520000;
 6 struct Trie{//数组形式 
 7     int Next[MAXN][N],Fail[MAXN],End[MAXN],root,tot;//大小为所以匹配字符串的总和 
 8     int newnode(){//结构体内部用 
 9         for(int i=0;i<N;i++) Next[tot][i]=-1;
10         End[tot++]=0;
11         return tot-1;
12     }
13     void init(){
14         tot=0;
15         root=newnode();
16     }
17     void insert(char buf[]){
18         int len=strlen(buf);
19         int now=root;//now是temp指针 
20         for(int i=0;i<len;i++){
21             int k=buf[i]-'a';
22             if(Next[now][k]==-1)  Next[now][k]=newnode();//next数组代表的是下一个字符索引 
23             now=Next[now][k];
24         }
25         End[now]++;//end数组是当前字符串的个数.字典中可能有相同的单词,若只算一次,改为1. 
26     }
27     void build(){//构造fail指针,后缀是某些前缀 
28         queue<int>que;
29         Fail[root]=root;
30         for(int i=0;i<N;i++){ 
31             if(Next[root][i]==-1) Next[root][i]=root;
32             else{
33                 Fail[Next[root][i]]=root;
34                 que.push(Next[root][i]);
35             }
36         } 
37         while(!que.empty()){//bfs,会将所有的匹配子串都遍历到 
38             int now=que.front();
39             que.pop();
40             for(int i=0;i<N;i++){
41                 if(Next[now][i]==-1) Next[now][i]=Next[Fail[now]][i];
42                 else{
43                     Fail[Next[now][i]]=Next[Fail[now]][i];
44                     que.push(Next[now][i]);
45                 }
46             }
47         }
48     }
49     int query(char buf[]){
50         int len=strlen(buf),now=root,res=0;
51         for(int i=0;i<len;i++){
52             now=Next[now][buf[i]-'a'];
53             int temp=now;
54             while(temp!=root){
55                 res+=End[temp];
56                 End[temp]=0;//模式串只在主串中匹配一次就可以了,若匹配次数算作n次,次数不必置0 
57                 temp=Fail[temp];
58             }
59         }
60         return res;
61     }
62 };
63 Trie ac;
64 char buf[1000003];
65 int main(){
66     int T,n;
67     ios::sync_with_stdio(0); 
68     cin>>T;
69     while(T--){
70         ac.init();
71         cin>>n;
72         for(int i=0;i<n;i++){
73             cin>>buf;
74             ac.insert(buf);
75         }
76         ac.build();//不要忘记build 
77         cin>>buf;
78         int ans=ac.query(buf);
79         cout<<ans<<"\n";
80     }
81     return 0;
82 } 

 

posted @ 2017-09-11 03:11  Elpsywk  阅读(126)  评论(0编辑  收藏  举报