zoukankan      html  css  js  c++  java
  • 【HDU】2222 Keywords Search

    【算法】AC自动机

    【题解】本题注意题意是多少关键字能匹配而不是能匹配多少次,以及可能有重复单词。

    询问时AC自动机与KMP最大的区别是因为建立了trie,所以对于目标串T与自动机串是否匹配只需要直接访问对应结点,而不用真的比较。

    因此可以预处理出拥有对应节点的失配串,不用一次一次跑前跑去找一样的。

    然后还有就是一个结点可能对应多个串,所以需要last使统计答案完整。

    AC自动机的细节标注在代码里了。

    AC自动机过程:

    [trie]

    for 长度

    if(!ch[u][c])初始化,ch[u][c]=++sz;

     else u=ch[u][c];

    val[u]=...;

    [getfail]

    初始进队

    队:u

      for 26(处理u点后续节点)

        if(!u)ch[x][c]=ch[p[x][c],continue;(没有该点,则考虑直接走失配直到有此点的串,由于层层前推实际上前一个即可)

        u进队;(有此点)

        int j=p[x];

        while(j>0&&!ch[j][c])j=p[j];(走失配直到有此点的串

        p[u]=ch[j][c];(记录失配边)

        last[u]=val[p[u]]?p[u]:last[p[u]];(记录同结尾价值点)

    [find]

    [askans]

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxnode=500010,maxn=10010,maxlen=1000010;
    int val[maxnode],sz,ch[maxnode][30],p[maxnode],last[maxnode],q[10010];
    long long ans;
    char s[maxlen];
    int idx(char c){return c-'a'+1;}
    void trie(char s[])
    {
        int u=0,m=strlen(s+1);
        for(int i=1;i<=m;i++)
         {
             int c=idx(s[i]);
             if(!ch[u][c])
              {
                  sz++;
                  memset(ch[sz],0,sizeof(ch[sz]));//初始化 
                  val[sz]=0;//初始化 
                  ch[u][c]=sz;
             }
            u=ch[u][c];
         }
        val[u]++;
    }
    void getfail()
    {
        int head=0,tail=0;//初始队列不能有队头! 
        p[0]=0;last[0]=0;//trie根初始化 
        for(int c=1;c<=26;c++)
         {
             int u=ch[0][c];
             if(u){p[u]=0;last[u]=0;q[tail++]=u;}
         }
        while(head!=tail)
         {
             int x=q[head++];if(head>10000)head=0;
             for(int c=1;c<=26;c++)
              {
                  int u=ch[x][c];
                  if(!u){ch[x][c]=ch[p[x]][c];continue;}//直接得到可匹配字符串,无则为0。 
                  q[tail++]=u;if(tail>10000)tail=0;
                  int j=p[x];
                  while(j>0&&!ch[j][c])j=p[j];
                  p[u]=ch[j][c];
                  last[u]=val[p[u]]?p[u]:last[p[u]];
             }
         }
    }
    void askans(int j)
    {
        while(j)
         {
             ans+=val[j];
             val[j]=0;
             j=last[j];
         }
    }
    void find(char s[])
    {
        int m=strlen(s+1);
        int j=0;
        for(int i=1;i<=m;i++)
         {
             int c=idx(s[i]);
             j=ch[j][c];//直接得到 
             if(val[j])askans(j);
              else if(last[j])askans(last[j]);
         }
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
         {
             int n;
            scanf("%d",&n);
            sz=0;//根节点标号为0 
            memset(ch[0],0,sizeof(ch[0]));//初始化根节点即可,建树中需要会继续清理,保持有效与无效结点中间始终存在断层。 
            for(int i=1;i<=n;i++)
             {
                 scanf("%s",s+1);
                 trie(s);//传过去的一定要是s,不能是s+1 
             }
            getfail();
            scanf("%s",s+1);
            ans=0;
            find(s);
            printf("%lld
    ",ans);
         }
        return 0;
    }
    View Code

    AC自动机

  • 相关阅读:
    区间dp_学习笔记
    状态压缩dp_学习笔记
    第十一届蓝桥杯C/C++ J题网络分析(带权并查集水题)
    状态机dp学习笔记_AcWing
    洛谷P4052 [JSOI2007]文本生成器(AC自动机+DP)
    洛谷P5840 [COCI2015]Divljak (AC自动机+fail树上dfs序+树上差分线段树维护)
    洛谷P3401 [USACO12JAN]Video Game G(AC自动机+记忆化搜索)
    HDU3613 Best Reward (exKMP/manacher)
    洛谷P2375 [NOI2014]动物园(KMP+倍增优化)
    ICPC2017南宁站题解(A,E,F,H,I,J,L,M)
  • 原文地址:https://www.cnblogs.com/onioncyc/p/6623293.html
Copyright © 2011-2022 走看看