Study Notes: AC automaton

Here \ (AC \) do not understand good too ......
let a lot of text strings run mode string \ (KMP \) , full name \ (Aho-Corasick \; automaton
\) is amazing,Like pasta machine.
The linear string into tree \ (Trie \) , and it is senseless to force the \ (Next [] \) array incomprehensible to mismatch pointer \ (Fail \) .
Gangster reference \ (yyb \) , then:
\ [Trie \ text {mismatch pointer is pointing to the tree: mismatching pointer along its parent node, all the way up until you find the letter of the current node has a child node that subnode} \]

Photo Pirates again it:

So we can start to build a normal \ (Trie \) :
Here is a structure:

struct node
{
    int kid[28];//对应的儿子节点(a-0,z-25)
    int end,fail;//分别是有几个子串在此终结,fail指针
}ac[MAXN];

Insertion (they all are)

void add(char *s)
{
    int len=strlen(s),u=0;
    for(int i=0;i<len;i++)
    {
        int j=s[i]-'a';
        if(!ac[u].kid[j]) ac[u].kid[j]=++cnt;
        u=ac[u].kid[j];
    }
    ac[u].end++;
}

The next step is to find the mismatch pointer for each node: the
idea is this:
For each node, enumerate all possible son node (a - z), if the existence of this node, put the son node mismatch pointer to his father misfit son nodes corresponding to the pointer.
Then you might ask: if he father mismatch corresponding node pointer is not it?
\ (qwq \) , it is natural to direct to \ (0 \) a.
Then think:

ah, if there is no child node, you subtract a virtual pointing to his father misfit son node pointer corresponding sub-node.
Code implementation may be realized through queue:

void build() 
{
    queue<int> q;
    int u=0;
    for(int i=0;i<26;i++)
    {
        if(ac[u].kid[i]) ac[ac[u].kid[i]].fail=0,q.push(ac[u].kid[i]);;
        
    }
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=0;i<26;i++)
        {
            if(ac[u].kid[i])
            {
                ac[ac[u].kid[i]].fail=ac[ac[u].fail].kid[i];
                q.push(ac[u].kid[i]);
            }
            else ac[u].kid[i]=ac[ac[u].fail].kid[i];
        }
    }
    return;
}

Later, we can match up to achieve automatic!
Generally enough for jumping mismatch son node pointer for each node.
To note a node labeled statistics (statistics marked the end of the diet -1), in order to avoid repetitive operations.
That's it:

int countt(char *s)
{
    int len=strlen(s),u=0;
    for(int i=0;i<len;i++)
    {
        u=ac[u].kid[s[i]-'a'];
        for(int k=u;k&&ac[k].end!=-1;k=ac[k].fail)
        {
            ans+=ac[k].end;
            ac[k].end=-1;
        }
    }   
    return ans;
}

Well, \ (AC \) simple tutorial automaton has been completed, then do the board main topic:
topic Link: P3808 [template] AC automaton (simple version)
Yes, this question as I \ (AC \ ) the first \ (300 \) questions, there are some deep thought of it (you know).
The following glue Code:

\(Code\):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1000005;
struct node
{
    int kid[28];
    int end,fail;
}ac[MAXN];
int cnt=0,ans=0;
int n;
char ch[MAXN];
void add(char *s)
{
    int len=strlen(s),u=0;
    for(int i=0;i<len;i++)
    {
        int j=s[i]-'a';
        if(!ac[u].kid[j]) ac[u].kid[j]=++cnt;
        u=ac[u].kid[j];
    }
    ac[u].end++;
}
void build() 
{
    queue<int> q;
    int u=0;
    for(int i=0;i<26;i++)
    {
        if(ac[u].kid[i]) ac[ac[u].kid[i]].fail=0,q.push(ac[u].kid[i]);;
        
    }
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(int i=0;i<26;i++)
        {
            if(ac[u].kid[i])
            {
                ac[ac[u].kid[i]].fail=ac[ac[u].fail].kid[i];
                q.push(ac[u].kid[i]);
            }
            else ac[u].kid[i]=ac[ac[u].fail].kid[i];
        }
    }
    return;
}
int countt(char *s)
{
    int len=strlen(s),u=0;
    for(int i=0;i<len;i++)
    {
        u=ac[u].kid[s[i]-'a'];
        for(int k=u;k&&ac[k].end!=-1;k=ac[k].fail)
        {
            ans+=ac[k].end;
            ac[k].end=-1;
        }
    }   
    return ans;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",ch);
        add(ch);
    }
    build();
    scanf("%s",ch);
    printf("%d\n",countt(ch));
    return 0;
} 

Also prescribe board questions (so many), the first cuckoo of it, so I slowly more.

Guess you like

Origin www.cnblogs.com/tlx-blog/p/12457428.html