hdu2222(ac自动机)

链接:点击打开链接

题意:给出一个字典和一个模式串,问模式串中出现几个字典中的单词

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int siz=500005;
struct node{
    int c[26];
    int dis,fail;
}s[siz];
int rt;
void in(char ss[]){
    int i,u;
    u=0;
    for(i=0;ss[i];i++){
        if(s[u].c[ss[i]-'a']==0)
        s[u].c[ss[i]-'a']=rt++;
        u=s[u].c[ss[i]-'a'];
    }
    s[u].dis++;                                 //字典中可能有相同的单词
}
void getfail(){
    int u,v,i,j,tmp;
    queue qu;
    qu.push(0);
    while(qu.size()){
        u=qu.front();
        qu.pop();
        for(i=0;i<26;i++){
            if(v=s[u].c[i]){
                if(u==0)
                s[v].fail=0;
                else{
                    tmp=s[u].fail;
                    while(tmp&&s[tmp].c[i]==0){
                        tmp=s[tmp].fail;
                    }
                    s[v].fail=s[tmp].c[i];
                }
                qu.push(v);
            }
        }
    }
}
int ac(char ss[]){
    int i,j,u,v,sum;
    u=sum=0;
    getfail();
    for(i=0;ss[i];i++){
        while(u&&s[u].c[ss[i]-'a']==0)
        u=s[u].fail;
        v=u=s[u].c[ss[i]-'a'];
        while(s[v].dis){                        //每个单词只能被统计一次,所以
            sum+=s[v].dis;                      //每一次fail需一直往回走,并且
            s[v].dis=0;                         //路过的节点都清零,其实因为这个
            v=s[v].fail;                        //条件,复杂度比理论上来说要退化很多啊....
        }
    }
    return sum;
}
int main(){                                     //推荐看hiho一下第四周去学习ac自动机,
    int n,i,j,t;                                //博客上应该是没有比那个讲的更详细的
    char ss[siz<<1];
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        rt=1;
        memset(s,0,sizeof(s));
        for(i=1;i<=n;i++){
            scanf("%s",ss);
            in(ss);
        }
        scanf("%s",ss);
        printf("%d\n",ac(ss));
    }
    return 0;
}


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