您的位置:首页 > 其它

HDU-2222 Keywords Search(AC自动机)

2016-07-23 22:48 295 查看
字典树+KMP
AC自动机 最基本的入门题了,就是求目标串中出现了几个模式串。

#include<cstdio>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e6 + 5;
struct node{
int nxt[26],ed;
void Init(){
for(int i=0;i<26;i++) nxt[i]=-1;
ed=0;
}
}L[maxn];
char st[maxn];
int tot,fail[maxn];
void add(){
int len=strlen(st),tmp,now=0;
for(int i=0;i<len;i++){
tmp=st[i]-'a';
if(L[now].nxt[tmp]==-1){
L[++tot].Init();
L[now].nxt[tmp]=tot;
}
now=L[now].nxt[tmp];
}
L[now].ed++;  //单词结尾
}
void build(){
queue<int>q;
int now=0;
fail[now]=now;
for(int i=0;i<26;i++){    //第1次循环时处理与root相连的字符,因为第一个字符不匹配需要重新匹配,所以第一个字符都指向root
if(L[now].nxt[i]==-1)
L[now].nxt[i]=now;
else{
fail[L[now].nxt[i]]=now;
q.push(L[now].nxt[i]);   //如果存在则入队
}
}
while(!q.empty()){
now=q.front();
q.pop();
for(int i=0;i<26;i++){
if(L[now].nxt[i]==-1)       //如果now下面没有该字符,则重新匹配
L[now].nxt[i]=L[fail[now]].nxt[i];
else{                          //如果now下面有该字符,该字符的重新匹配应指向now重新匹配的下面一个字符,并且把该字符入队
fail[L[now].nxt[i]]=L[fail[now]].nxt[i];
q.push(L[now].nxt[i]);
}
}
}
}
int query(){
int len=strlen(st),now=0,tmp,ret=0;
for(int i=0;i<len;i++){
now=L[now].nxt[st[i]-'a'];
tmp=now;
while(tmp){     //如果tmp变成root则退出循环
ret+=L[tmp].ed;   //如果此处为某个单词的结尾,则加上在此结尾的单词数
L[tmp].ed=0;     //加完后标记为0,避免重复
tmp=fail[tmp];   //搜索下一个重新匹配
}
}
return ret;
}
int main(){
int T;
// freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
int n;
tot=0;
L[0].Init();   //每次要把root初始化
scanf("%d",&n);
while(n--){
scanf("%s",st);
add();
}
build();
scanf("%s",st);
printf("%d\n",query());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: