• 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
  • 相关阅读:
    09-2:跳台阶
    09:菲波那切数列
    08:旋转数组的最小值
    07:用两个栈实现队列
    06:重建二叉树
    05:从尾到头打印链表
    04:替换字符
    centos7安装Jenkins更改默认端口并配置Ldap服务器进行用户认证
    Jira配置openLdap服务器进行用户认证
    定时自动从FTP服务器取数据脚本
  • 原文地址:https://www.cnblogs.com/mountaink/p/10505722.html
Copyright © 2020-2023  润新知