羅区[P3808(テンプレート)ACオートマトン(簡易版)

トピックリンク

(テンプレート)ACオートマトン(簡易版)

トピックの背景

これは単純なAC自動マシンテンプレートのタイトルです。
正しさの定数を検出するためのアルゴリズム。
カードOJを防ぐために、データの2組のみが正しい根拠を確保するために、悪意のある提出しないでください。
ヒント:そこの言葉は、このデータのタイトルに繰り返され、単語数回計算しなければならない、してくださいノートを繰り返し

タイトル説明

与えられた(N \)\モードの文字列とを(1 \)\テキスト文字列、文字列内のテキスト文字列に登場したモデルの数を見つけます。

入力形式

最初の行が\(N- \) パターン文字列の数を表し、
以下\(N- \)線各パターン文字列、
文字列の行以下。

出力フォーマット

番号は、その答えを示し

サンプル入力

2 
および
AA 
AA

サンプル出力

2

説明/ヒント

\(subtask1 \) [ \(50pts \) ]:\(\ SUM長(パターン文字列)<= 10 ^ 6、長さ ( 。。テキスト文字列)<= 10 ^ 6、N- = 1 \) ; \
(subtask2 \) [ \(50pts \) ]:\(\ SUM長(パターン文字列)<= 10 ^ 6、長さ ( 文字列)<= 10 ^ 6 \)

問題の解決策

ACオートマトンボードの問題、それオートマトン直接交流の観点インチ
まず第一に、それは、トライます
KMPが、それは、なり、第二に
、これら二つのものを組み合わせたことはACオートマトンです。
まず、私たちは辞書ツリーに応じて文字列の入力モードを内蔵し、
その後、ルートからツリーを走査し、この木KMPを実行します。
KMPでは、各点のために、我々は見つける必要がある\(次\) 終点接尾辞(プレフィックス長の先頭少ない現在のポイントの長さよりも)、最長プレフィックススクラッチに等しいです。
しかし、AC自動機のために、このプレフィックスは、ツリーの他の子ノードがあるかもしれない、必ずしも現在のポイントの祖先ではありません。
下図のように:

\(4 \)のノード数\(次\)にポイントする必要がある\(3 \)ノードの数、
我々はこの問題を解決するために非常に巧妙な方法を使用して、
限り広いラインでツリーを検索し、検索、
各ノードがあるため、(次に\)\点の深さ値は、このノード点よりも小さくなければならない、このノードに(次に\)\点の値は、によって指さ(次に\)\値が良好なためである必要があります(多少前後)。
その後、我々はKMPのためのアルゴリズムに従ってください\(次回\)うまく値。


:次は、我々はいくつかの小さな最適化を検討
KMPが求めて考慮に入れて\(次の\を)値は、多くの場合、ルート・ノードを見つけるときに、
我々は見つけるまで続けることを期待して(\次)\現在のノードの条件を\(次回\)のノードを検索し、同じサブノードの手紙、する必要はありません
その後、現在のノード\(\次の)ノードのノードに対応するが、空でなければならない
、我々は、このノードに対応する場所を維持するのであれば\(\次)このノードにもエッジこの場所に類似している値((\次\) )、その後求める)\次は(\あなたは直接の値が必要と置き換えることができたときに場所を見つけることができます。
図以下:

\(6 \)ノードの数\(次へ\)点値(\ 7 \) 次いで\(6 \)ノードの数\( "D" \)息子があった(\ 8)\
個人的に私は最適化されたコードのこの組み合わせは、それを理解しやすいと思います。
その後、各検索\(次\)は、時間複雑である場合(O(1)\)\(ただ、最適化の一定のレベルは、あなたが追加することはできません)

コードの場合:

#include<bits/stdc++.h>
using namespace std;
int n;
char c[1000009];
struct aa{
    int s;
    int up;
    int to[30];
}p[1000009];
int len;
int ans;
void add(){
    int l=strlen(c);
    int u=0;
    for(int j=0;j<l;j++){
        if(p[u].to[c[j]-'a']) u=p[u].to[c[j]-'a'];
        else {p[u].to[c[j]-'a']=++len;u=len;}
    }
    p[u].s++;
}
int q[1000009],l=1,r=0;
void bfs(){
    for(int j=0;j<='z'-'a';j++)
        if(p[0].to[j]) q[++r]=p[0].to[j];
    while(l<=r){
        int u=q[l++];
        for(int j=0;j<='z'-'a';j++){
            if(p[u].to[j]){
                p[p[u].to[j]].up=p[p[u].up].to[j];
                q[++r]=p[u].to[j];
            }else p[u].to[j]=p[p[u].up].to[j];
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int j=1;j<=n;j++){
        scanf("%s",c);
        add();
    }
    bfs();
    scanf("%s",c);
    int l=strlen(c);
    int uu=0;
    for(int j=0;j<l;j++){
        uu=p[uu].to[c[j]-'a'];
        int k=uu;
        while(k && p[k].s!=-1){
            ans+=p[k].s;
            p[k].s=-1;
            k=p[k].up;
        }
    }
    printf("%d",ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/linjiale/p/12219321.html