研究ノート:ACオートマトン

ここでは\(AC \)は ......あまりにも良いと理解していない
テキスト文字列の多くはモード文字列を実行してみましょう(KMP \)\、フルネームを\(アホ- Corasick \;オートマトン
\) 、素晴らしいですパスタマシンと同様に
線形ツリーに文字列\(トライ\) 強制的に無意味である\(次に[] \)ミスマッチポインタのアレイ不可解\(失敗\)
ギャング参照\(yyb \)そして、:
\ [トライ\テキスト{不一致ポインタがツリーを指している:その親ノードに沿ってポインタを不整合、すべての方法をあなたは現在のノードが子ノードを持っているの手紙を見つけるまで、サブノード} \]

:写真パイレーツ再びそれは

我々が通常の構築を開始することができますので、\(トライを\)
ここでは構造体です:

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

次のステップは、各ノードの不一致ポインタを見つけることです:
アイデアはこれです:
各ノードについて、すべての可能な息子ノード列挙-このノードの存在は、息子ノードのミスマッチを置けば、(z)を父親のミスフィットの息子へのポインタはポインタに対応するノード。
次に、あなたが頼むかもしれない:ノードポインタを対応する彼の父親の不一致はそれではないですか?
\(qwq \) に向けることが自然である(\ 0)\
次に考える:

子ノードが存在しない場合は、ああ、あなたが引く仮想サブノードに対応する父親のミスフィット息子ノードポインタにポインティングを。
コードの実装は、キューを介して実現されてもよいです。

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;
}

その後、我々は自動的に達成するために一致することができます!
各ノードの不一致息子のノードポインタをジャンプするための一般的には十分。
ノードラベルされた統計情報に注意することは繰り返し動作を避けるために、(統計はダイエット-1の終わりをマークされています)。
これは次のとおりです。

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;
}

まあ、\(AC \)簡単なチュートリアルオートマトンが完了した後、ボードメイントピックの操作を行います。
トピックリンク:P3808 [テンプレート] ACオートマトン(簡易版)
Iとしてはい、この質問を\(AC \ )最初の\(300 \)の質問に、それのいくつかの深い考えは(あなたが知っている)があります。
以下ののりコード:

\(コード\)

#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;
} 

また、ボードの(非常に多くの)質問、それの最初のカッコウを処方し、Iのでゆっくりより。

おすすめ

転載: www.cnblogs.com/tlx-blog/p/12457428.html