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

    推荐blog

     认为上面这篇blog已经讲述的十分清楚(一定要画图多手动模拟,,才能感受AC自动机的奥妙),所以解释两个我想了很久也没想明白的问题 (是基于代码的)

    1.为什么要用BFS太蠢了QWQ

    2.连接fail时的一些特殊情况到底是怎么处理的

    例如当前有一颗这样的树:

    我们已经按照操作,搜索到了标红节点,按照AC自动机的思想连fail边,因为我们已经处理过它的父亲节点c节点的fail值,所以d节点的fail值应该等于。。讲不清了大概是这样连边:

    然而虚拟d点的编号为0,那这样红色d点岂不是相当于连到了顶点,但其实不是,我们也可以看出来d点应该连在第3列的d点上

    但这是怎么处理的呢?因为是BFS,是按照深度由浅到深进行处理的,所以虚拟点其实已经处理过且值已变成另一个d点了

    就像是这样:

    推荐题目:洛谷P3808

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int num,ans;
    struct{
        int vis[28];
        int fail;
        int end;
    }a[1000006];
    void build(string s){
        int i,l,now=0;
        l=s.length();
        for(i=0;i<l;i++){
            if(a[now].vis[s[i]-'a']==0){
                num++;
                a[now].vis[s[i]-'a']=num;
            }
            now=a[now].vis[s[i]-'a'];
        }
        a[now].end++;
    }
    void fail(){
        queue<int>q;
        int now,i;
        for(int i=0;i<26;++i){
              if(a[0].vis[i]!=0)
                  q.push(a[0].vis[i]);
        }//一定要有,若只是将0放入队列中,那第一层字母将会指向它自己,然而它应该指向0点
        while(!q.empty()){
            now=q.front();q.pop();
            for(i=0;i<26;i++){
                if(a[now].vis[i]){
                    a[a[now].vis[i]].fail=a[a[now].fail].vis[i];
                    q.push(a[now].vis[i]);
                }
                else a[now].vis[i]=a[a[now].fail].vis[i];
            }
        }
    }
    void find(string s){
        int i,l,now,j;
        l=s.length();
        now=0;
        for(i=0;i<l;i++){
                now=a[now].vis[s[i]-'a'];
                for(j=now;j&&a[j].end!=-1;j=a[j].fail){
                    ans+=a[j].end;
                    a[j].end=-1;
                }
        }
    }
    int main(){
        int i,j,l,n;
        string s;
        cin>>n;
        for(i=1;i<=n;i++){
            cin>>s;
            build(s);
        }
        fail();
        //for(i=1;i<=num;i++)printf("%d %d ",a[i].fail,a[i].end);
        cin>>s;
        find(s);
        printf("%d",ans);
    }
  • 相关阅读:
    shell加密为二进制可执行文件
    lua自写限制并发访问模块
    centos虚拟机中挂新硬盘
    lua文件修改为二进制文件
    常用一些命令方法
    常用问题处理方法
    CVE-2010-3333
    Kernel Stack Overflow(转)
    NULL Pointer Dereference(转)
    Linux内核漏洞利用-环境配置(转)
  • 原文地址:https://www.cnblogs.com/Jessica-Cao/p/13551841.html
Copyright © 2011-2022 走看看