hdu 2222 AC自动机入门

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值