ac 自动机

来源:互联网 发布:平板上的淘宝怎么开店 编辑:程序博客网 时间:2024/06/11 01:57
/*以hdu 3065为例ac自动机=kmp+trie与kmp的思想是一样的,不过实现起来就有相当多的细节问题了。1.建立字典树是必须的,ch[i][j],i是节点编号,j是儿子。每一个节点都隐含有MAX_SIZE个儿子的指针,0表示该儿子不存在,其他值表示她的位置2.算出失配边,对于ch[i][j]!=0的处理方法与kmp中是相同的。但对于ch[i][j]=0的处理有两种,①不处理,直接跳过,continue②把ch[i][j],赋值为 ch[Fail[i]][j],这样做的原因是简化代码,提高程序效率。分析:在kmp中,有这么一句话while(j>=0&&T[i]!=S[j+1])j=Fail[j];即: 当扫到目标串的i位时,不匹配则沿着失配边一直走下去。同样 ac自动机中也是这样:当扫到目标串的i位时,不匹配则沿着失配边一直走下去。②的处理先一步走完了相连的第一个失配边。失配边是按节点的深度递推下来的,而失配边边必然连向了一个深度较小的节点,较小的点的失配边已经处理,这样ch[i][j]直接变成了第一个能够与T正在处理的那一位匹配的节点的编号或0(根节点)。当开始与T匹配时,就不再需要沿失配边走的语句了,直接j=ch[j][i],i是T的那一位的值(说的模糊,看代码就知道了)3.开始与T匹配了,处理与kmp几乎完全相同,就是2.②的变化。。对于不同的题处理也就不同了,当有多个目标串T对Ac_Trie操作时,一定要保证Ac_Trie不变!!*/#include<cstdio>#include<cstring>#include<iostream>#include<queue>#include<string>#include<algorithm>using namespace std;int const MAX_NODE=1010*55;int const MAX_SIZE=128;char mp[1010][55];int ans[1010];struct Ac_Trie{    int ch[MAX_NODE][MAX_SIZE],Fail[MAX_NODE],value[MAX_NODE];/*ch[][]用来建字典树,Fail[]表示失配边,value[]存储的是字典树中该节点存储的信息value[i]=-1,表示从root到编号为i的节点所形成的字符串不存在ch[i][j],表示编号为i的节点的第j个儿子节点,ch[i][j]=0表示此路径不存在,否则她的值为节点i沿边j走下去的下一个节点编号其中ch[i][j]=-1,0,可赋予不同的意义,视题意而定*/    int root,tot;    int newnode()    {        memset(ch[tot],0,sizeof(ch[tot]));        value[tot++]=-1;        return tot-1;    }    void init()    {        tot=0;        root=newnode();    }    void insert(char *s,int key)//构造trie树    {        int len=strlen(s);        int u=root;        for(int i=0;i<len;i++)        {            int v=s[i];            if(!ch[u][v])                ch[u][v]=newnode();            u=ch[u][v];        }        value[u]=key;    }    void build()//构造自动机    {        queue<int>Q;        Fail[root]=root;        for(int i=0;i<MAX_SIZE;i++)            if(ch[root][i])            {                Fail[ch[root][i]]=root;                Q.push(ch[root][i]);            }        while(!Q.empty())        {            int now=Q.front();Q.pop();            for(int i=0;i<MAX_SIZE;i++)            {                if(ch[now][i])                {                    Fail[ch[now][i]]=ch[Fail[now]][i];                    Q.push(ch[now][i]);                }                else ch[now][i]=ch[Fail[now]][i];            }        }    }    void Ac(char *T)//与目标串匹配    {        int len=strlen(T);        int u=root;        for(int i=0;i<len;i++)        {            int v=T[i];            u=ch[u][v];            int temp=u;            while(temp)            {                if(value[temp]!=-1)                    ans[value[temp]]++;                temp=Fail[temp];            }        }    }};char T[2000010];Ac_Trie Ac;int main(){    int n,m;    while(scanf("%d",&n)!=EOF)    {        Ac.init();        for(int i=1;i<=n;i++)        {            scanf("%s",mp[i]);            Ac.insert(mp[i],i);        }        Ac.build();        scanf("%s",T);        memset(ans,0,sizeof(ans));        Ac.Ac(T);        for(int i=1;i<=n;i++)        {           // cout<<ans[i]<<endl;            if(ans[i])                printf("%s: %d\n",mp[i],ans[i]);        }    }    return 0;}

0 0
原创粉丝点击