zoukankan      html  css  js  c++  java
  • AC自动机

    AC自动机--树上KMP

    在博主还没懂其精髓并有足够语言组织能力之前,先挂着,以免把别人带入坑中。

    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    
    #define ll long long
    #define db double
    #define inf 0x7fffffff
    #define rg register int
    
    using namespace std;
    
    struct su{
        int fail; //匹配失败后跳到哪一个节点
        int son[26]; //儿子的地址
        int end;  //有多少个模式串在这个节点结束
    }ac[1000001];
    
    int n,top;
    string s;
    
    inline int qr(){ char ch;
        while((ch=getchar())<'0'||ch>'9');
        int res=ch^48;
        while((ch=getchar())>='0'&&ch<='9')
            res=res*10+(ch^48);
        return res;
    }
    
    inline void build(){
        int l=s.length(),now=0,*son;
        for(rg i=0;i<l;++i){
            son=&ac[now].son[s[i]-'a']; //开个指针方便快捷
            if(!*son)*son=++top; //没有这个字母的位置就新开一个
            now=*son; //把下一位字母放进去
        }++ac[now].end; //这个模式串在这个节点结束
    }
    
    inline void failed(){
        queue<int> q; //用BFS来给树上KMP做预处理
        for(rg i=0;i<26;++i)
            if(ac[0].son[i])
                ac[ac[0].son[i]].fail=0,//初始化
                q.push(ac[0].son[i]); //根节点的子节点都指向根节点
        rg i,j,*son,next;
        while(!q.empty()){
            i=q.front(); q.pop();
            for(j=0;j<26;++j){
                son=&ac[i].son[j]; //当前的节点
                next=ac[ac[i].fail].son[j]; //当前节点匹配失败时转向的下一个节点
                if(*son){
                    ac[*son].fail=next; //对应68,69行构成(局部)的KMP  #1!
                    q.push(*son); //预备下一层
                }else *son=next; //对应第67行,共同构成一个(整体)的KMP #2!
            }
        }
    }
    
    inline int find(){
        int l=s.length(),now=0,ans=0;
        for(rg i=0;i<l;++i){
            now=ac[now].son[s[i]-'a']; //匹配下一层,对应59行
            for(rg j=now;j&&ac[j].end>-1;j=ac[j].fail) //原理模仿的KMP算法
                ans+=ac[j].end,ac[j].end=-1; //and改成-1:每个字符串最多匹配一次
        }return ans;
    }
    
    int main(){ n=qr();
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        for(rg i=1;i<=n;++i)
            cin>>s,build();//把模式串加入AC自动机
        failed(); cin>>s;
        printf("%d",find());//直接输出
        return 0;
    }
    
  • 相关阅读:
    Ubuntu 杂音 alsa*
    安装YouCompleteMe
    vimrc
    Linux Windows 修改键盘映射
    VMware Workstation+Linux+Xshell+Xftp+MySQL+SQLyog 配置
    leetcode Merge Intervals
    leetcode Remove Duplicates from Sorted Array II
    用栈实现二叉树的非递归中序遍历
    nth_element 测试程序
    Windows 程序设计
  • 原文地址:https://www.cnblogs.com/812-xiao-wen/p/10324676.html
Copyright © 2011-2022 走看看