POJ2222 Keywords Search AC自动机模板

题意:给出一些单词,求多少个单词在字符串中出现过(单词表单词可能有相同的,这些相同的单词视为不同的分别计数)(如果单词x在字符串中出现一次而在单词表中有两个则ans+2,在字符串中出现两次而单词表中有一个则ans+1)
AC自动机模板题,之前学了总觉得不扎实,现在有底了现在终于可以去敲心头大恨,兴奋!!!
代码
 1 #include<cstdio>
 2 #include<cstring>
 3 const int maxn=10010;
 4 const double eps=1e-8;
 5 const long long modn=1000;
 6 int n;
 7 char a[51]={};
 8 char b[100*maxn]={};
 9 struct trie{
10     int next[26];
11     bool exist;
12     int count;
13     int fail;
14 }e[maxn*50]={};
15 int tot,ans;
16 int q[maxn*50]={};
17 
18 void init(int x,int k,int j){
19     if(j>k){ 
20         e[x].exist=1;
21         e[x].count++;
22         return; 
23     }
24     int z=a[j]-'a';
25     if(!e[x].next[z])
26         e[x].next[z]=++tot;
27     init(e[x].next[z],k,j+1);
28 }
29 void fir(){
30     memset(e,0,sizeof(e)); memset(q,0,sizeof(q));
31     tot=ans=0;
32 }
33 void doit(){
34     int head=0,tail=0,x,y,f;
35     q[0]=0;
36     while(head<=tail){
37         x=q[head++];
38         for(int i=0;i<26;i++){
39             if(e[x].next[i]){
40                 y=e[x].next[i];
41                 if(x!=0){
42                     f=e[x].fail;
43                     while((!e[f].next[i]) && f )
44                         f=e[f].fail;
45                     e[y].fail=e[f].next[i];
46                 }q[++tail]=y;
47             }
48         }
49     }
50 }
51 void find(){
52     scanf("%s",&b);
53     int k=std::strlen(b);
54     int x=0,z,y;
55     for(int i=0;i<k;i++){
56         z=b[i]-'a';
57         while( (!e[x].next[z])&& x){
58             x=e[x].fail;
59         }x=e[x].next[z]; y=x;
60         while(y&&e[y].count){
61             ans+=e[y].count;
62             e[y].count=0;
63             y=e[y].fail;
64         }
65     }
66 }
67 int main(){
68     int T;scanf("%d",&T);
69     while(T-->0){
70         fir();
71         scanf("%d",&n);
72         for(int i=1;i<=n;i++){ 
73             scanf("%s",&a);
74             init(0,std::strlen(a)-1,0); 
75         }
76         doit();
77         find();
78         printf("%d\n",ans);
79     }
80     return 0;
81 }
View Code

 更新:

整理模板的时候发现自己原来的代码有问题。这个新版本应该没问题了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn=10100;
 9 int n,siz;
10 char ch[60]={};
11 char str[maxn*100]={};
12 struct trie{
13     int sig[26];
14     int cnt;
15     int vis;
16     int fail;
17 }t[maxn*60];int tot=0;
18 int q[maxn*60]={};int head=0,tail=0;
19 void fir(){
20     tot=0;memset(t,0,sizeof(t));//memset(q,0,sizeof(q));
21 }
22 void init(int x,int j){
23     if(j>siz-1){ t[x].cnt++; return; }
24     int z=ch[j]-'a';
25     if(!t[x].sig[z])t[x].sig[z]=++tot;
26     init(t[x].sig[z],j+1);
27 }
28 void build_fail(){
29     int head=0,tail=0,x,y,f;q[0]=0;
30     while(head<=tail){
31         x=q[head++];
32         for(int i=0;i<26;i++)
33             if(t[x].sig[i]){
34                 y=t[x].sig[i];
35                 if(x){
36                     f=t[x].fail;
37                     while((!t[f].sig[i])&&f)
38                         f=t[f].fail;
39                     t[y].fail=t[f].sig[i];
40                 }q[++tail]=y;
41             }
42     }
43 }
44 int get_num(){//字符串中包含的单词数量,重复的不记录,
45     //如果单词x在字符串中出现一次而在单词表中有两个则ans+2
46     //在字符串中出现两次而单词表中有一个则ans+1
47     int ans=0,x=0,y,z;
48     for(int i=0;i<siz;i++){
49         z=str[i]-'a';
50         while((!t[x].sig[z])&&x)
51             x=t[x].fail;
52         x=t[x].sig[z];y=x;
53         while(y&&(!t[y].vis)){//保证了每个结尾只访问一次
54             ans+=t[y].cnt;
55             t[y].vis=1;t[y].cnt=0;
56             y=t[y].fail;
57         }
58     }
59     return ans;
60 }
61 int main(){
62     int T;scanf("%d",&T);
63     while(T-->0){
64         fir();
65         scanf("%d",&n);
66         for(int i=1;i<=n;i++){scanf("%s",ch);siz=strlen(ch);init(0,0);}
67         build_fail();
68         scanf("%s",str);siz=strlen(str);
69         printf("%d\n",get_num());
70     }
71     return 0;
72 }
new

 

转载于:https://www.cnblogs.com/137shoebills/p/7786493.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值