AC自动机模板

学习链接:点击进入
功能

解决多对字符串之间的相互匹配问题

fail指针

fail是失配指针,如果此时匹配失败,那么,我们就要到达这个指针指向的位置继续常数匹配
fail [ i ] 为与以 i 节点为结尾的串的后缀有最大公共长度的前缀的结尾编号,也就是说
fail指针指向的节点所代表的串,是最长的、能与后缀匹配的,且在Trie中出现过的前缀所代表的节点。

代码
const int maxn=1e6+10;

int trie[maxn][26]; //字典树
int sum[maxn];      //记录该单词出现次数
int fail[maxn];     //失败时的回溯指针
int cnt = 0;

void init()
{
	memset(trie,0,sizeof(trie));
	memset(sum,0,sizeof(sum));
	memset(fail,0,sizeof(fail));
	cnt=0;
}

void insert(char *str)
{
    int p=0,len=strlen(str);
    for(int i=0;i<len;i++)
	{
        int c=str[i]-'a';
        if(!trie[p][c])
            trie[p][c]=++cnt;
        p=trie[p][c];
    }
    sum[p]++;      //当前节点单词数+1
}
void getfail()
{
    queue<int>q;
    for(int i=0;i<26;i++)//第二层的fail指针提前处理一下
	{                 
        if(trie[0][i])
		{
            fail[trie[0][i]]=0;//指向根节点
            q.push(trie[0][i]);
        }
    }
    while(!q.empty())
	{
        int now=q.front();
        q.pop();
        for(int i=0;i<26;i++)
		{      //查询26个字母
            if(trie[now][i])//存在这个子节点
			{
                fail[trie[now][i]]=trie[fail[now]][i]; 
                //子节点的fail指针指向当前节点的
                //fail指针所指向的节点的相同子节点
                q.push(trie[now][i]);
            }
            else//不存在这个子节点 当前节点的这个子节点指向当前节点fail指针的这个子节点 
                trie[now][i]=trie[fail[now]][i];
        }
    }
}
int query(char *str)
{
    int p=0,ans=0;
    int len=strlen(str);
    for(int i=0;i<len;i++)
	{    //遍历文本串
        p=trie[p][str[i]-'a'];  //从s[i]点开始寻找
        for(int j=p;j&&sum[j]!=-1;j=fail[j])
		{
            //一直向下寻找,直到匹配失败(失败指针指向根或者当前节点已找过).
            ans+=sum[j];
            sum[j]=-1;    //将遍历国后的节点标记,防止重复计算
        }
    }
    return ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值