hdu 2222 AC自动机入门

来源:互联网 发布:钢铁力量天王战车数据 编辑:程序博客网 时间:2024/06/03 11:17

http://blog.csdn.net/niushuai666/article/details/7002823

这篇博客讲得不错

主要是要能理解这个trie图



有3个重要的指针,分别为p, p->fail, temp。

1.指针p,指向当前匹配的字符。若p指向root,表示当前匹配的字符序列为空。(root是Trie入口,没有实际含义)。

2.指针p->fail,p的失败指针,指向与字符p相同的结点,若没有,则指向root

3.指针temp,测试指针 ,在建立fail指针时有寻找与p字符匹配的结点的作用。

详见代码注释


#include<bits/stdc++.h>using namespace std;const int N=10005;const int maxlen=1000132;const int maxn=10005*50;int trie[maxn][26];int fail[maxn];int tag[maxn];int sz;queue<int >Q;struct Aho{    int root=0;    int newnode()//静态创建新节点    {        memset(trie[sz],-1,sizeof trie[sz]);        tag[sz]=0;        sz++;        return sz-1;    }    void init()//初始化    {        sz=0;        newnode();    }    void insert(char s[])   //插入字符串构建ac自动机,构建trie树    {        int len=strlen(s),p=0;;        for (int i=0; i<len; i++)        {            int id=s[i]-'a';            if (trie[p][id]==-1)                trie[p][id]=newnode();            p=trie[p][id];        }        tag[p]++;   //结束标记    }    void getfail() //构建自动机fail指针    {        while(!Q.empty()) Q.pop();        fail[root]=root;            //root指向root        for (int i=0; i<26; i++)        {            if (trie[root][i]==-1)//第一个字符不存在,指向root                trie[root][i]=root;            else    //第一个字符的fail指针指向root            {                fail[trie[root][i]]=root;                Q.push(trie[root][i]);   //并放入队列,待bfs扩展            }        }        while(!Q.empty())        {            int u=Q.front();    //取扩展节点            Q.pop();            for (int i=0; i<26; i++)//遍历所有子节点            {                if (trie[u][i]==-1)//如果不存在,则子节点直接指向fail[u]节点的对应子节点                    trie[u][i]=trie[fail[u]][i];                else     //如果存在,则该节点的fail指针指向fail[u]节点对应的子节点                {                    fail[trie[u][i]]=trie[fail[u]][i];                    Q.push(trie[u][i]);     //继续扩展                }            }        }    }} aho;char ss[55];char s[maxlen];int main(){    int t;    scanf("%d",&t);    while(t--)    {        aho.init();        int n;        cin>>n;        for (int i=0; i<n; i++)        {            scanf("%s",ss);            aho.insert(ss);        }        aho.getfail();        scanf("%s",s);        int len=strlen(s);        int p=aho.root;        int ans=0;        for (int i=0; i<len; i++)        {            int idx=s[i]-'a';             p=trie[p][idx];             int tmp=p; //取出当前字符在自动机上对应的节点             while(tmp!=aho.root)//如果有fail节点则一直往上跳,直到跳回root表示没有了fail后继              {                  ans+=tag[tmp];//累计答案                  tag[tmp]=0;//清空tag标记                  tmp=fail[tmp];//跳到fail后继节点              }        }        printf("%d\n",ans);    }    return 0;}





0 0
原创粉丝点击