HDU 2222 keyword search(AC自动机)

#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define M 1000001 #define N 26 char s[M],word[2*N]; typedef struct link{ link *next[N],*fail; int cn; link(){ memset(next,NULL,sizeof(next)); fail=NULL,cn=0; } }tire; link *q[M]; void InsertTire(tire *bt,char *word){ //插入建立的字典树 int i=0,len=strlen(word); link *temp=bt; while(i<len){ int j=word[i]-'a'; if(temp->next[j]==NULL) temp->next[j]=new link(); temp=temp->next[j]; i++; } temp->cn++; //以 temp 这个指针的为尾的后缀单词增加一个 例如 she ,he ,那么 temp->cn:=2。 } void Bulid_Aho_Corasick_Autometion(tire *bt){ //创建AC自动机,自身模式匹配 int head=0,tail=0; bt->fail=NULL; //树的根节点的失败指针都是指向空的。 q[tail++]=bt; // q 为 BFS节点求失败指针域的一个模拟队列。 while(head<tail){ link *t=q[head++],*p=NULL; //t指向队头 待求失败指针的 一个域。 for(int i=0;i<N;i++){ //从26个字母 ‘A’-‘B’扫描 if(t->next[i]!=NULL){ //如果字典树在当前的单位的 第i个域存在 ,则 加入队列。 q[tail++]=t->next[i]; if( t==bt ){ // 如果当前节点为根节点,那么它的失败指针域便指回根。 t->next[i]->fail=bt; continue; } p=t->fail; // 现在 p 指向 t的失败指针域。 while(p!=NULL && p->next[i]==NULL) // 这个循环表示找到滑动指针域最小,并且它的 第'i'个字符是存在的。 p=p->fail; t->next[i]->fail=(p==NULL)?bt:p->next[i]; // 如果p指回到NULL,表示向上以前没有和它匹配成功的(具体匹配类似KMP) } } } } int SearchString(tire *bt,char *s){ //查找树中,在模式串中子串的个数。 int sum=0,i=0,len=strlen(s); link *p=bt,*temp; while(i<len){ int j=s[i]-'a'; while( p->next[j]==NULL && p!=bt ) p=p->fail; p=p->next[j]; if(p==NULL) p=bt; temp=p; while(temp!=bt && temp->cn!=-1){ sum+=temp->cn; //如果是单词后缀,也许它也是0。 temp->cn=-1; // 防止第二次加入,标记为-1. temp=temp->fail; } i++; } return sum; } int main(){ int t; cin>>t; while(t--){ tire *bt=new link(); int n; cin>>n; getchar(); while(n--){ gets(word); InsertTire(bt,word); } Bulid_Aho_Corasick_Autometion(bt); gets(s); cout<<SearchString(bt,s)<<endl; } return 0; }

你可能感兴趣的:(struct,null,search,ini,BT)