Fourth AC zi dong ji(Aho-Corasick Automation) of life
9A(其实不止交了10发...) 感言:
一开始多组数据这种小数据还是...无伤大局,因为改完以后还是wa...
一:
最后发现是wa在构造fail指针的时候在建立临时指针查询有没有匹配到的fail,在没有匹配到的时候,结点的fail的指针要指向根。
二(重要感言):
在查询时,往上回溯fail指针的时候,fail指针是一定会最终回溯到根的,而且,比如当前查询到的主串是ABCDEF,fail指针可能会一直传递最终到根,但是并不是都有效啊!这里还要注意,fail指针传递过去,找到的是子串,还是本来那个串的后缀串,为什么说是子串:如果有模式串ABCD,ABCDEF,主串是ACBDEF,主串到D的时候已经处理掉了ABCD,这个情况下是不会用到fail指针的功效了,或者这里没有有效的后缀串;什么时候会用fail指针呢,如果有模式串CD,BCD,ABCDEF,主串是ACBDEF,那么在主串到D的时候会通过fail指针找到BCD,然后在找到CD,所以我们能得出,fail指针的回溯,当前串(比如ABCD)最后那个D是一直不会变的,可以说fail指针都是D的fail指针!
三:
不要依赖模板...
推荐几个数据:
2
CC
AAA
ooxxCC%dAAAoen....ENDooxxCC%dAAAoen....ENDooxxCC%dAAAoen....END
2
ABCDE
BCD
ABCD
2
ABCDE
BCD
ABCDEF
//#include <bits/stdc++.h> #include<iostream> #include<cstdio> #include<queue> #include<string.h> #include<algorithm> using namespace std; typedef long long LL; /* 题意: 求不同的病毒出现的次数,未出现的不需要输出 AAA其中AA出现2次; 思路: 那我存的应该是编号了,编号都不同。 */ const int N=5e4+10; struct Trie { int id; Trie *next[26],*fail; }; Trie q[N],*root; int tol,ans[1010],n; char ss[1010][51]; Trie* Creat() { Trie *p; p=&q[tol++]; p->fail=NULL; p->id=0; for(int i=0; i<26; i++) p->next[i]=NULL; return p; } void Insert(char *str,int id) { Trie *p=root; int index,len=strlen(str); for(int i=0; i<len; i++) { index=str[i]-'A'; if(p->next[index]==NULL) p->next[index]=Creat(); p=p->next[index]; } p->id=id; } void Build_Ac() { queue<Trie*>que; que.push(root); while(!que.empty()) { Trie *p=que.front();que.pop(); for(int i=0; i<26; i++) { if(p->next[i]!=NULL) { if(p==root) p->next[i]->fail=root; else { Trie *temp=p->fail; while(temp!=NULL)//找匹配的 { if(temp->next[i]!=NULL) //找到 { p->next[i]->fail=temp->next[i]; break; } temp=temp->fail; } if(temp==NULL) //如果没有找到匹配的,则fail指向根 p->next[i]->fail=root; } que.push(p->next[i]); } } } } char word[2000010]; void Query() { int res=0; int index,len=strlen(word); Trie *p=root; for(int i=0; i<len; i++) { if(!(word[i]>='A'&&word[i]<='Z')){ p=root; continue; } index=word[i]-'A'; while(p->next[index]==NULL && p!=root) p=p->fail; p=p->next[index]; if(p==NULL) p=root; Trie *temp=p; while(temp!=root) //回溯到根 { ans[temp->id]++; //这里这样写没事,因为我不会用到id为0的,任他+ temp=temp->fail; } } for(int i=1; i<=n; i++) { if(ans[i]) printf("%s: %d ",ss[i],ans[i]); } } int main() { while(~scanf("%d",&n)) { tol=0; root=Creat(); for(int i=1; i<=n; i++) { ans[i]=0; scanf("%s",ss[i]); Insert(ss[i],i); } getchar(); Build_Ac(); gets(word); Query(); } return 0; }
;