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 */

 

 
 

你可能感兴趣的:(AC自动机)