zoukankan      html  css  js  c++  java
  • P3796 【模板】AC自动机

    传送门

    AC自动机的模板

    简单的理解就是字典树上的KMP

    注意数组不要开太大

    不然每次memset耗时太多

    有一个小优化

    每次走 fail 边找匹配时只有一些会更新答案

    那么就可以把没用的fail边压缩掉

    设 g[x] 表示从 x 点一直走 fail 边,走到的第一个有结束标记的点

    那么找匹配时就只有要 g 边

    然后就是模板了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    using namespace std;
    const int N=5e4+7;
    int len,n;
    char s[1000007];
    inline void read_s()//文本串比较大,可以用快读加速
    {
        char ch=getchar(); len=0;
        while(ch<'a'||ch>'z') ch=getchar();
        while(ch>='a'&&ch<='z')
        {
            s[++len]=ch;
            ch=getchar();
        }
    }
    int c[N][27],pd[N],fail[N],g[N],cnt;
    char a[1670][670]; int l[570];
    inline void clr()//清空AC自动机
    {
        memset(c,0,sizeof(c));
        memset(pd,0,sizeof(pd));
        memset(fail,0,sizeof(fail));
        memset(g,0,sizeof(g));
        cnt=0;
    }
    inline void ins(int num)//插入单词到自动机(跟字典树没区别)
    {
        int u=0;
        for(int i=0;i<l[num];i++)
        {
            int v=a[num][i]-'a'+1;
            if(!c[u][v]) c[u][v]=++cnt;
            u=c[u][v];
        }
        pd[u]=num;
    }
    queue <int> q;
    inline void pre()//预处理fail和g
    {
        for(int i=1;i<=26;i++)
            if(c[0][i]) q.push(c[0][i]);
        while(!q.empty())
        {
            int u=q.front(); q.pop();
            for(int i=1;i<=26;i++)
            {
                int v=c[u][i];
                if(!v) c[u][i]=c[fail[u]][i];//失配了直接走失配边
                else
                {
                    fail[v]=c[fail[u]][i];
                    g[v]= pd[fail[v]] ? fail[v] : g[fail[v]];//处理g
                    q.push(v);
                }
            }
        }
    }
    int mx,ans[167];
    inline void query()//AC自动机匹配(好像跟字典树也没什么区别)
    {
        memset(ans,0,sizeof(ans));
        int u=0;
        for(int i=1;i<=len;i++)
        {
            u=c[u][s[i]-'a'+1];
            if(pd[u]) ans[pd[u]]++;
            for(int j=g[u];j;j=g[j])
                ans[pd[j]]++;
            //计算匹配
        }
        mx=0;
        for(int i=1;i<=n;i++)
            mx=max(mx,ans[i]);
        cout<<mx<<endl;
        for(int i=1;i<=n;i++)
            if(ans[i]==mx)
                printf("%s
    ",a[i]);
    }
    int main()
    {
        while(1)
        {
            scanf("%d",&n); if(!n) break;
            clr();
            for(int i=1;i<=n;i++)
            {
                scanf("%s",a[i]);
                l[i]=strlen(a[i]);
                ins(i);
            }
            pre();
            read_s();
            query();
        }
        return 0;
    }
  • 相关阅读:
    构造方法
    方法调用时参数传递问题
    空指针异常
    Go安装,配置
    干货-MySQL
    websocket
    Tornado的使用
    socket客户端异步、socket服务端异步
    celery分布式队列实现:实时显示任务执行到哪一步
    celery+django实践
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9672809.html
Copyright © 2011-2022 走看看