简单提一下起源好了:这个东西最早出现于贝尔实验室,是很常用的多模式匹配算法(对比于\(KMP\)的单模式串匹配)
算法基础是\(Trie\)与\(KMP\)思想(只有思想)。
AC自动机通俗的讲是Trie上的KMP。
比较重要的一点就是他的失配指针,可以支持在一次匹配失败后自动跳转至下一个匹配位置从而避免从头重新匹配,降低复杂度。
这玩意儿的复杂度是\(O(n)\)的。
代码:
Code
template<int node_num,int set_size>
class AC_automation
{
private:
typedef char* str;
int tot;
int ch[node_size][set_size];
int fail[node_size];
int cnt[node_size];
public:
AC_automation(){tot=1;}
void insert(str);
void get_fail();
int query(str);
}
template<int node_size,int set_size>
void AC_automation<node_size,set_size>::insert(str s)
{
int p=1;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int c=s[i]-'a'+1;
if(!ch[p][c]) ch[p][c]=++tot;
p=ch[p][c];
}
cnt[p]++;
}
template<int node_size,int set_size>
void AC_automation<node_size,set_size>::get_fail()
{
queue<int> q;
fail[1]=1;
for(int i=1;i<=26;i++)
{
if(!ch[1][i]) ch[1][i]=1;
else fail[ch[1][i]]=1,q.push(ch[1][i]);
}
while(!q.empty())
{
int x=q.front(),q.pop();
for(int i=1;i<=26;i++)
{
if(ch[x][i]) fail[ch[x][i]]=ch[fail[x]][i],q.push(ch[x][i]);
else ch[x][i]=ch[fail[x]][i];
}
}
}
template<int node_size,int set_size>
int AC_automation<node_size,set_size>::query(str s)
{
int p=1;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int x=s[i]-'a'+1;
p=ch[p][x];
for(int j=p;j&&cnt[j];j=fail[j])
{
ans+=cnt[j];
cnt[j]=0;
}
}
}