AC自动机模板题

      AC自动机学习博客

  AC自动机理解要点:

    1)fail指针指向的是每个节点,在字典树上和这个节点后缀相同的最长单词,每次都这样匹配,必定不会漏过答案。

    2)字典树建立后,会在bfs求fail阶段把字典树变成一个字典树图(不知道理解的对不对),就是把字典树的末尾节点再往下添加一层,并且连接到fail指针指向的相同位子的儿子。

   两道模板题和AC代码。

    P3808

 

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000010;
char s[maxn],p[maxn];
int trie[maxn][26],cntword[maxn],fail[maxn],cnt=0;
int n;
void insert(char *s){
    int root=0;
    int si=strlen(s);
    for(int i=0;i<si;i++)
    {
        int Next=s[i]-'a';
        if(!trie[root][Next])trie[root][Next]=++cnt;
        root=trie[root][Next];
    }
    cntword[root]++;
}
void getfail(){
    queue<int >q;
    for(int i=0;i<26;i++)
    {
        if(trie[0][i]){
            q.push(trie[0][i]);
        }
    }
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[now][i]){
                fail[trie[now][i]]=trie[fail[now]][i];
                q.push(trie[now][i]);
            }else{
                trie[now][i]=trie[fail[now]][i];
            }
        }
    }
}
int query(char *s){
    int now=0,ans=0;
    int si=strlen(s);
    for(int i=0;i<si;i++)
    {
        now=trie[now][s[i]-'a'];
        for(int j=now;j&&cntword[j]!=-1;j=fail[j])
        {
            ans+=cntword[j];
            cntword[j]=-1;
        }
    }
    return ans;
}
int main(){
    cin>>n;
    while(n--)
    {
        scanf("%s",p);
        insert(p);
    }
    fail[0]=0;
    getfail();
    scanf("%s",s);
    cout<<query(s)<<endl;
}
View Code

  P3796

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const int maxn=1000010;
char s[maxn],p[maxn];
int trie[maxn][26],cntword[maxn],fail[maxn],cnt=0;
int n;
int num[maxn];
map<int,string>dio;
void insert(char *s){
    int root=0;
    int si=strlen(s);
    for(int i=0;i<si;i++)
    {
        int Next=s[i]-'a';
        if(!trie[root][Next])trie[root][Next]=++cnt;
        root=trie[root][Next];
    }
    dio[root]=s;
    cntword[root]++;
}
void getfail(){
    queue<int >q;
    for(int i=0;i<26;i++)
    {
        if(trie[0][i]){
            q.push(trie[0][i]);
        }
    }
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=0;i<26;i++)
        {
            if(trie[now][i]){
                fail[trie[now][i]]=trie[fail[now]][i];
                q.push(trie[now][i]);
            }else{
                trie[now][i]=trie[fail[now]][i];
            }
        }
    }
}
void query(char *s){
    int now=0,ans=0;
    int si=strlen(s);
    for(int i=0;i<si;i++)
    {
        now=trie[now][s[i]-'a'];
        for(int j=now;j&&cntword[j]!=-1;j=fail[j])
        {
            //ans+=cntword[j];
            if(cntword[j]>0){
                num[j]+=cntword[j];
            }
            //cntword[j]=-1;
        }
    }
}
void init(){
    clr(trie,0);
    clr(num,0),clr(cntword,0);
    dio.clear();
}
int main(){
    while(scanf("%d",&n),n){
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%s",p);
            insert(p);
        }
        int p,maxx=0;
        vector<int >ans;
        fail[0]=0;
        getfail();
        scanf("%s",s);
        query(s);
        for(int i=1;i<=cnt;i++)
        {
            if(num[i]>maxx){
                maxx=num[i];
                ans.clear();
                ans.push_back(i);
            }else if(num[i]==maxx)
            {
                ans.push_back(i);
            }
        }
        cout<<maxx<<endl;
        for(int i=0;i<ans.size();i++)
        {
            cout<<dio[ans[i]]<<endl;
        } 
    }
}
View Code

 

posted @ 2019-03-10 16:17  光芒万丈小太阳  阅读(133)  评论(0编辑  收藏  举报