AC自动机

前言

其实AC自动机就是多模式匹配,运用trie和kmp把时间复杂度优化到线性的O(N)。

一、建trie

trie就不多说了,相信大家都会

void put()
{
    int now=1,len=strlen(s1+1);
    for(int i=1;i<=len;i++)
    {
        if(!trie[now].c[s1[i]-'a']) trie[now].c[s1[i]-'a']=++tot;
        trie[trie[now].c[s1[i]-'a']].deep=trie[now].deep+1;
        now=trie[now].c[s1[i]-'a'];
    }
    trie[now].w=1;
}

二、构建fail(失败指针)

fail(失败指针)其实就是类似于kmp的next数组,是AC自动机的核心。
如果会kmp的话,应该也不能难解。
可以通过一幅图来理解一下
这里写图片描述

void makefail()
{
    int head=0,tail=1,now=1;
    d[1]=1;
    trie[1].fail=0;
    while(head<tail)
    {
        int k=d[++head],p=0;
        for(int i=0;i<26;i++)
        {
            if(!trie[k].c[i]) continue;
            p=trie[k].c[i];
            int z=trie[k].fail;
            while(z && !trie[z].c[i]) z=trie[z].fail;
            trie[p].fail=trie[z].c[i];
            trie[p].fail=trie[p].fail?trie[p].fail:1;
            d[++tail]=p;
        }
    }
}

三、查询

当每次确定了一个节点后顺着fail构成了链向上走,避免漏算以现在搜到的状态为后缀的字符串。

int find()
{
	int j=1;
	for(int i=1;i<=n;i++)
	{
		int index=s[i]-'a';
		while(j!=1 && !trie[j].c[index]) j=trie[j].fail;
		j=trie[j].c[index];
		j=j?j:1;
		int p=j;
		while(p!=1)
		{
			if(trie[p].w) ans++;
			p=trie[p].fail;
			trie[p].w--;
		}
	}
}

当然,不能直接打模板,根据每到题目的不同来分析运用,有时要加点优化。


模板题【GDOI2013模拟4】贴瓷砖

原文地址:https://www.cnblogs.com/chen1352/p/9048120.html