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 }
更新:
整理模板的时候发现自己原来的代码有问题。这个新版本应该没问题了。
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 }