【模板】AC自动机

我觉得AC自动机的难点和核心是构建失败指针,父亲的失败指针的儿子(son2)中有和儿子(son1)相同的,即为son1的失败指针

这里写图片描述

还是有个不懂的地方:第90行,跪求大佬赐教

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
struct Tree{
    int nxt[26];
    int count;
    int fail;
    void init()
    {
        memset(nxt,-1,sizeof(nxt));
        int fail=0;
        int count=0;
    } 
}s[500009];
char str[100009],des[100009];
int n,sind=1,stu[500009];
void ins()//构建询问串trie树 
{
    int len=strlen(str);
    int i,j,ind=0;
    for(i=0;i<len;i++)
    {
        j=str[i]-'a';
        if(s[ind].nxt[j]==-1)
        {
            s[sind].init();
            s[ind].nxt[j]=sind;
            sind++;
        }
        ind=s[ind].nxt[j];
    }
    s[ind].count++;//增加离根节点这条路径上字符串的个数,一条路上可能不止一个单词  
}
void make_fail()
{
    int qh=0,qt=0,ind,ind_f;
    for(int i=0;i<26;i++)
    {
        if(s[0].nxt[i]!=-1)
          stu[++qt]=s[0].nxt[i];//先把根下面链接的点入队 
    }
    while(qh<qt)
    {
        ind=stu[++qh];
        for(int i=0;i<26;i++)
        {
            if(s[ind].nxt[i]!=-1)//如果有 i ,求 i 的fail指针 
            {
                stu[++qt]=s[ind].nxt[i];//入队 
                ind_f=s[ind].fail;//父亲的失败指针 
                int son=s[ind].nxt[i];

                while(ind_f>0&&s[ind_f].nxt[i]==-1)
                  ind_f=s[ind_f].fail;//父亲失败指针的儿子中有相同的,即为son的失败指针 

                if(s[ind_f].nxt[i]!=-1)
                  ind_f=s[ind_f].nxt[i];

                s[son].fail=ind_f;
            }
        }
    }
}
int fd()
{
    int cnt=0,i,j,len;
    int ind=0;
    len=strlen(des);
    for(i=0;i<len;i++)
    {
        j=des[i]-'a';
        while(ind>0&&s[ind].nxt[j]==-1)//一直在寻找合适的 fail 指针 ,如果是ind=0停止循环,直接判断 
         ind=s[ind].fail;

        if(s[ind].nxt[j]!=-1)//如果找到了成功的fail,那么开始计数 
        {
            ind=s[ind].nxt[j];
            int p=ind;

            while(p>0&&s[p].count!=-1)
            {
                cnt+=s[p].count;
                s[p].count=-1;
                p=s[p].fail;    //ind ? p ? 跳跳跳 
            }
        }
    }
    return cnt;
}
int main()
{
    s[0].init();//初始化根节点 !!! 
    scanf("%d\n",&n);
    for(int i=1;i<=n;i++)
    {
        gets(str);
        ins();
    }
    make_fail();

    gets(des);
    int ans=fd();

    printf("%d",ans);
    return 0; 
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值