`
暴风雪
  • 浏览: 377483 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

[AC自动机]hdoj 2222:Keywords Search

阅读更多

大致题意:

    给出n个模式串(长度不超过50),和一个文本串(长度不超过1000000),求出有多少个模式串在这个文本串中出现过。


 

大致思路:

    标准的AC自动机问题,主要是学习模版,理解自动机的匹配机制。

 

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include <algorithm>
using namespace std;
const int inf=1<<28;
const int nMax=500;
const int mMax=500005;
class node{
public:
    int id;
    int vis;  //前缀记录标志
    node *next[26],*fail;
    node(){
        vis=0;
        fail=NULL;
        for(int i=0;i<26;i++)next[i]=NULL;
    }
}*root,*que[mMax];

void insert(char *s){    //构造前缀树
    int i;
    node *r=root;
    int l=strlen(s);
    for(i=0;i<l;i++){
        int loc=s[i]-'a';
        if(r->next[loc]==NULL){
            r->next[loc]=new node();
        }
        r=r->next[loc];
    }
    r->vis++;
}

void acAuto(){      //用bfs为每个节点设定fail指针
    int i,head=0,tail=0;
    node *p,*tmp;
    root->fail=NULL;
    que[tail++]=root;
    while(head<tail){
        tmp=que[head++];
        for(i=0;i<26;i++){
            if(tmp->next[i]==NULL)continue;
            if(tmp==root){
                tmp->next[i]->fail=root;
            }
            else {
                for(p=tmp->fail;p!=NULL;p=p->fail){
                    if(p->next[i]!=NULL){
                        tmp->next[i]->fail=p->next[i];
                        break;
                    }
                }
                if(p==NULL){
                    tmp->next[i]->fail=root;
                }
            }
            que[tail++]=tmp->next[i];
        }
    }
}

int search(char *msg){
    int i,idx,ans=0;
    node *p=root,*tmp;
    for(i=0;msg[i];i++){
        idx=msg[i]-'a';
        while(p->next[idx]==NULL&&p!=root){
            p=p->fail;
        }
        p=p->next[idx];
        if(p==NULL)p=root;
        for(tmp=p;tmp!=NULL&&tmp->vis!=-1;tmp=tmp->fail){
            ans+=tmp->vis;
            tmp->vis=-1;
        }
    }
    return ans;
}

int main(){
    int cas,n,i;
    char str[52],text[1000002];
    scanf("%d",&cas);
    while(cas--){
        scanf("%d",&n);
        root=new node();
        while(n--){
            scanf("%s",str);
            insert(str);
        }
        acAuto();
        scanf("%s",text);
        printf("%d\n",search(text));
    }
    return 0;
}
 

 

另附上静态tire树版本,可以省去不少生成新对象的时间(动态250ms,静态180)

 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include <algorithm>
using namespace std;
const int inf=1<<28;
const int nMax=500;
const int mMax=500005;
class node{
public:
    int id;
    int vis;  //前缀记录标志
    node *next[26],*fail;
//    node(){
//        vis=0;
//        fail=NULL;
//        for(int i=0;i<26;i++)next[i]=NULL;
//    }
}*root,*que[mMax],num[5000000];
int x;
node *newnode(){
    node * p = num + x++;
    for(int i = 0; i <26; i++){
        p->next[i] = NULL;
    }
    p->fail=NULL;
    p->vis=0;
    return p;
}

void insert(char *s){    //构造前缀树
    int i;
    node *r=root;
    int l=strlen(s);
    for(i=0;i<l;i++){
        int loc=s[i]-'a';
        if(r->next[loc]==NULL){
            r->next[loc]=newnode();
        }
        r=r->next[loc];
    }
    r->vis++;
}

void acAuto(){      //用bfs为每个节点设定fail指针
    int i,head=0,tail=0;
    node *p,*tmp;
    root->fail=NULL;
    que[tail++]=root;
    while(head<tail){
        tmp=que[head++];
        for(i=0;i<26;i++){
            if(tmp->next[i]==NULL)continue;
            if(tmp==root){
                tmp->next[i]->fail=root;
            }
            else {
                for(p=tmp->fail;p!=NULL;p=p->fail){
                    if(p->next[i]!=NULL){
                        tmp->next[i]->fail=p->next[i];
                        break;
                    }
                }
                if(p==NULL){
                    tmp->next[i]->fail=root;
                }
            }
            que[tail++]=tmp->next[i];
        }
    }
}

int search(char *msg){
    int i,idx,ans=0;
    node *p=root,*tmp;
    for(i=0;msg[i];i++){
        idx=msg[i]-'a';
        while(p->next[idx]==NULL&&p!=root){
            p=p->fail;
        }
        p=p->next[idx];
        if(p==NULL)p=root;
        for(tmp=p;tmp!=NULL&&tmp->vis!=-1;tmp=tmp->fail){
            ans+=tmp->vis;
            tmp->vis=-1;
        }
    }
    return ans;
}

int main(){
    int cas,n,i;
    char str[52],text[1000002];
    scanf("%d",&cas);
    while(cas--){
        x=0;
        scanf("%d",&n);
        root=newnode();
        while(n--){
            scanf("%s",str);
            insert(str);
        }
        acAuto();
        scanf("%s",text);
        printf("%d\n",search(text));
    }
    return 0;
}
1
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics