AC自动机模板(hdu2222)

本文提供了一个AC自动机的数组写法实现模板,包括节点结构定义、插入操作、构建AC自动机以及查询过程。适用于模式匹配等应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚刚学习了AC 自动机,先记录一个数组写法的模板。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Max 26
#define N 1000005

struct node
{
    int next[Max];//每一个节点可以扩展到的字母
    int fail;//每一个节点的失配指针
    int count;
    void init()//构造
    {
        memset(next,-1,sizeof(next));
        fail=0;
        count=0;
    }
}s[N];
int num;//记录节点编号
char str[55];//模板串,单词
char ss[N];//母串
int q[N],tail,head;//队列相关信息
void cas_init()//在整个程序前构造root
{
    s[0].init();//初始化头结点
    num=1;//当前的节点数量为1
}
void insert()
{
    int len=strlen(str);
    int p=0,i,j;
    for(i=0;i<len;i++)
    {
        j=str[i]-'a';//求出字母在next中的编号
        if(s[p].next[j]==-1)//如果为空则构造新的,否则顺着上次的开始往下构造
        {
            s[num].init();//初始化当前节点
            s[p].next[j]=num++;//连向当前节点,并是num++来扩充节点
        }
        p=s[p].next[j];//向下遍历
    }
    s[p].count++;//增加离根节点这条路径
}
void build_ac()
{
    tail=head=0;//初始化队列
    int temp,p;
    for(int i=0;i<Max;i++)
    {
        if(s[0].next[i]!=-1)
        {
            q[tail++]=s[0].next[i];//和根节点相连的都入队
        }
    }
    while(tail!=head)
    {
        p=q[head++];//记录队首节点
        for(int i=0;i<Max;i++)//遍历首节点的next
        {
            if(s[p].next[i]!=-1)//如果节点next不为空
            {
                q[tail++]=s[p].next[i];//将儿子节点入队列
                temp=s[p].fail;//记录节点的失配指针指向
                while(temp>0&&s[temp].next[i]==-1)//当失配指针不为root时一直循环找到一的儿子节点不为空或到了root
                temp=s[temp].fail;
                if(s[temp].next[i]!=-1)//如果当前节点有儿子的话记录下来备用
                temp=s[temp].next[i];
                s[s[p].next[i]].fail=temp;//是当前节点的失配指针指向刚才记录的节点完成失配指针的构造
            }
        }
    }
}
void query()
{
    int len=strlen(ss);
    int p=0;
    int temp=0;
    int ans=0;
    for(int i=0;i<len;i++)
    {
        int id=ss[i]-'a';
        while(p>0&&s[p].next[id]==-1)//当前p指针不是root和找不到儿子时,一直找下去(及kmp的while)
        p=s[p].fail;//一直寻找失配指针
        if(s[p].next[id]!=-1)//找到适合的失配指针
        {
            p=s[p].next[id];//指向这个儿子节点,更新p的值进行下次匹配
            temp=p;
            while(temp>0&&s[temp].count!=-1)//temp > 0表示还没到root,count != -1表示指针前还有单词
            {
                ans+=s[temp].count;//加上有的单词个数
                s[temp].count=-1;//不重复计算
                temp=s[temp].fail;//一直寻找失配指针
            }
        }
    }
    printf("%d\n",ans);
}
int main()
{
    int n;
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        cas_init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",str);
            insert();
        }
        build_ac();
        scanf("%s",ss);
        query();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值