AC自动机

AC自动机:一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。

要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。

如果你对KMP算法和了解的话,应该知道KMP算法中的next函数(shift函数或者fail函数)是干什么用的。KMP中我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符,当A[i+1]≠B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配,而next函数恰恰记录了这个j应该调整到的位置。同样AC自动机的失败指针具有同样的功能,也就是说当我们的模式串在Tire上进行匹配时,如果与当前节点的关键字不能继续匹配的时候,就应该去当前节点的失败指针所指向的节点继续进行匹配。

AC自动机算法分为3步:
1.构造一棵Trie树
2.构造失败指针
3.模式匹配过程。
 
hdu2222,这个题就是AC自动机的裸题,但注意模式可以重复。
代码:
View Code
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string>
  4 #include <queue>
  5 using namespace std;
  6 const int maxnum=27;
  7 
  8 struct node
  9 {
 10     int count;
 11     node *next[maxnum];
 12     node *fail;
 13     node()
 14     {
 15         count=0;
 16         fail=NULL;
 17         int i;
 18         for(i=0;i<maxnum;i++)
 19             next[i]=NULL;
 20     }
 21 };
 22 node *root;
 23 queue<struct node *> q;
 24 
 25 void Insert(char *str)
 26 {
 27     node *pp=root;
 28     int k;
 29     while(*(str)!=0)
 30     {
 31         k=*str-'a';
 32         if(pp->next[k]==NULL)
 33             pp->next[k]=new node();
 34         pp=pp->next[k];
 35         if(*(str+1)==0)
 36             pp->count++;  //模式可以重复,所以++
 37         str++;
 38     }
 39 }
 40 
 41 void Delete(node *pp)
 42 {
 43     int i;
 44     for(i=0;i<maxnum;i++)
 45         if(pp->next[i]!=NULL)
 46             Delete(pp->next[i]);
 47     delete pp;     //删除pp指针所指的内容,pp地址不变
 48     pp=NULL;       //pp地址指向0,避免野指针
 49 }
 50 
 51 void Traversal(node *pp,string ss)
 52 {
 53     int i,flag;
 54     for(i=0;i<maxnum;i++)
 55     {
 56         flag=false;
 57         if(pp->next[i]!=NULL)
 58         {
 59             flag=true;
 60             string strtemp=ss;
 61             ss+=(char)(i+'a');
 62             if(pp->next[i]->count!=0) cout<<ss<<endl;
 63             Traversal(pp->next[i],ss);  //use p->next[i] instead of p=p->next[i];
 64             ss=strtemp;//ss return to old value
 65         }
 66     }
 67     if(!flag) return ;
 68 }
 69 
 70 void Build()
 71 {
 72     root->fail=NULL;
 73     q.push(root);
 74     node *temp,*pp;
 75     int i;
 76     while(!q.empty())
 77     {
 78         temp=q.front();
 79         q.pop();
 80         for(i=0;i<maxnum;i++)
 81             if(temp->next[i]!=NULL)
 82             {
 83                 if(temp==root)
 84                     temp->next[i]->fail=root;
 85                 else
 86                 {
 87                     pp=temp->fail;
 88                     while(pp!=NULL)
 89                     {
 90                         if(pp->next[i]!=NULL)
 91                         {
 92                             temp->next[i]->fail=pp->next[i];
 93                             break;
 94                         }
 95                         pp=pp->fail;
 96                     }
 97                     if(pp==NULL)
 98                         temp->next[i]->fail=root;
 99                 }
100                 q.push(temp->next[i]);
101             }
102     }
103 }
104 
105 int Query(char *str)
106 {
107     node *pp,*temp;
108     pp=root;
109     int k;
110     int cnt=0;
111     while(*str!=0)
112     {
113         k=*str-'a';
114         while(pp->next[k]==NULL && pp!=root)
115             pp=pp->fail;
116         pp=pp->next[k];
117         if(pp==NULL)
118             pp=root;
119         temp=pp;
120         while(temp!=root && temp->count!=-1)
121         {
122             cnt+=temp->count;
123             temp->count=-1;
124             temp=temp->fail;
125         }
126         str++;
127     }
128     return cnt;
129 }
130 
131 void check()
132 {
133     node *temp;
134     int i;
135     q.push(root);
136     while(!q.empty())
137     {
138         temp=q.front();
139         q.pop();
140         cout<<temp<<" "<<temp->fail<<endl;
141         for(i=0;i<maxnum;i++)
142             if(temp->next[i]!=NULL)
143                 q.push(temp->next[i]);
144     }
145 }
146 
147 int main()
148 {
149     char p[55],t[1000007];
150     int num,i,ans,m;
151     scanf("%d",&m);
152     while(m--)
153     {
154         root=new node();
155         scanf("%d",&num);
156         for(i=0;i<num;i++)
157         {
158         scanf("%s",p);
159         Insert(p);
160         }
161         scanf("%s",t);
162         Build();
163         ans=Query(t);
164         cout<<ans<<endl;
165         Delete(root);
166     }
167 
168     return 0;
169 }
170 
171 /*
172 1
173 5
174 he
175 her
176 say
177 she
178 shr
179 yarhshe
180 */

 

 
 
posted @ 2012-08-21 08:41  pushing my way  阅读(165)  评论(0编辑  收藏  举报