hdu 2222


AC自动机

要求对一个文本统计出现过的模板个数

理解了AC自动机的算法就很容易了


指针版

#include<queue>
#include<stdio.h>
#include<iostream>
#include<cstdio>
using namespace std;
struct node{
    int fl;
    node *next[26],*fail;
    node(){
        memset(next,0,sizeof next);
        fail=NULL;
        fl=0;
        
    }
};
char s[1000050],ss[1005];
void ins(node *rt,char mb[]){
    int i=0,x;
    node *tmp=rt;
    while(mb[i]){
        x=mb[i]-'a';
        if(tmp->next[x]==NULL)tmp->next[x]=new node();
        tmp=tmp->next[x];
        i++;
    }
    tmp->fl++;
}
queue<node *>q;
void build(node *rt){
    node *tmp;
    q.push(rt);
    while(!q.empty()){
        tmp=q.front();
        q.pop();
        for(int i=0;i<26;++i)
            if(tmp->next[i]){
              q.push(tmp->next[i]);
              node *p=tmp->fail;
                while(p){
                    if(p->next[i]){
                        tmp->next[i]->fail=p->next[i];
                        break;
                    }
                    p=p->fail;
                }
                if(!p)tmp->next[i]->fail=rt;
            }
    }
}
int query(node *rt){
    int i=0,cnt=0,x;
    node *tmp=rt;
    while(s[i]){
        x=s[i]-'a';
        while(!tmp->next[x]&&tmp!=rt)tmp=tmp->fail;
        tmp=tmp->next[x];
        if(!tmp)tmp=rt;
        node *p=tmp;
        
        while(p&&p->fl!=-1){
            cnt+=p->fl;
            p->fl=-1;
            p=p->fail;
        }
        i++;
    }
    
    return cnt;
}
int main(){
    int n;
    int t;scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        node *root=new node();
        for(int i=0;i<n;++i){
            scanf("%s",ss);
            ins(root,ss);
        }
        build(root);
        scanf("%s",s);
        printf("%d\n",query(root));
    }
    return 0;
}
数组版:(注意C++会TLE 可能与内存分配有关)
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<queue>
using namespace std;
#define M 510000
#define size 26
struct node{
    int ch[M][26],fail[M],end[M],cnt,root;
    int add(){
        ++cnt; memset(ch[cnt],-1,sizeof ch[cnt]);
        end[cnt]=0;
        return cnt;
    }
    void init(){
        cnt=0;root=add();
    }
    void ins(char s[]){
        int len=(int)strlen(s);int p=root;
        for(int i=0;i<len;++i){
            int x=s[i]-'a';
            if(ch[p][x]==-1)ch[p][x]=add();
            p=ch[p][x];
        }
        end[p]++;
    }
    queue<int>q;
    void build(){
        int p=root;fail[root]=root;
        for(int i=0;i<size;++i){
            if(ch[p][i]==-1) ch[p][i]=p;
            else { q.push(ch[p][i]); fail[ch[p][i]]=p;}
        }
        while(!q.empty()){
            p=q.front();q.pop();
            for(int i=0;i<size;++i){
                if(ch[p][i]==-1) ch[p][i]=ch[fail[p]][i];
                else{fail[ch[p][i]]=ch[fail[p]][i]; q.push(ch[p][i]);}
            }
        }
    }
    void query(char s[]){
        int len=(int)strlen(s),pos=root,ans=0;
        for(int i=0;i<len;++i){
            int x=s[i]-'a';
            int tmp=ch[pos][x]; pos=tmp;
            while(tmp!=root){
                ans+=end[tmp];end[tmp]=0;tmp=fail[tmp];
            }
        }
        printf("%d\n",ans);
    }
}x;
char s1[1005],s2[1100000];
int main(){
    int t,n;scanf("%d",&t);
    while(t--){
        scanf("%d",&n);x.init();
        for(int i=0;i<n;++i){
            scanf("%s",s1);
            x.ins(s1);
        }
        x.build();
        scanf("%s",s2);
        x.query(s2);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值