• AC自动机 HDU2222


    本文参考博客:

    https://blog.csdn.net/bestsort/article/details/82947639

    https://blog.csdn.net/creatorx/article/details/71100840

    https://blog.csdn.net/weixin_43923436/article/details/88635103?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

    先解释一下自动机,一般我们所说的自动机都是有限状态自动机,所有的状态都属于一个状态集S,另外有转移函数F,相当于是一种刺激,使得当前自动机的状态可以转移到另一个状态。AC自动机就是在Trie上加上了fail指针,fail指针是多模式匹配的关键,而KMP适用于单模式匹配。fail使得Trie树转变成为Trie图。AC自动机中用模式串建Trie树,然后用文本串进行匹配,所以复杂度为O(max{m*|P|,|S|})。

    下图可以简明的表示通过模式串构建成功的AC自动机的样子:

    红色圈标志单词的存在性,也就是树中存在的模式串,虚线就是fail指针的指向,fail指针的设计可以用图的层次遍历实现。fail其实就像KMP的next数组,这里的fail指向与当前结点有后缀的最深的路径的终点。

    匹配过程的重点有两个,1、,匹配成功,通过不断向下扩展达到红色结点(标记了单词的结尾),每次扩展到下一层之前不断通过fail指针向上转移,如果fail指针没有指向根节点,那么他代表的串一定是转移前结点代表的串的后缀,并且查看该后缀是否是单词 2、从now结点开始失配,从失配的位置转移到fail指针指向的下一个位置(注意,这个转移在fail构建的时候就已经设置好了,所以如果下个字符在fail指向结点的下一个位置匹配,则now也转移,否则失配,转到根节点),如上图,匹配shers到she失败后匹配最左边路径的rs路径。

    hdu2222是AC自动机的模板题,题目链接:http://icpc.njust.edu.cn/Problem/Hdu/2222/

    代码如下:(这道题时间卡的特别严格,写的代码竟被卡掉)

     kuangbin代码:

      1 //======================
      2 // HDU 2222
      3 // 求目标串中出现了几个模式串
      4 //====================
      5 #include <stdio.h>
      6 #include <algorithm>
      7 #include <iostream>
      8 #include <string.h>
      9 #include <queue>
     10 using namespace std;
     11 
     12 struct Trie
     13 {
     14     int next[500010][26],fail[500010],end[500010];
     15     int root,L;
     16     int newnode()
     17     {
     18         for(int i = 0;i < 26;i++)
     19             next[L][i] = -1;
     20         end[L++] = 0;
     21         return L-1;
     22     }
     23     void init()
     24     {
     25         L = 0;
     26         root = newnode();
     27     }
     28     void insert(char buf[])
     29     {
     30         int len = strlen(buf);
     31         int now = root;
     32         for(int i = 0;i < len;i++)
     33         {
     34             if(next[now][buf[i]-'a'] == -1)
     35                 next[now][buf[i]-'a'] = newnode();
     36             now = next[now][buf[i]-'a'];
     37         }
     38         end[now]++;
     39     }
     40     void build()
     41     {
     42         queue<int>Q;
     43         fail[root] = root;
     44         for(int i = 0;i < 26;i++)
     45             if(next[root][i] == -1)
     46                 next[root][i] = root;
     47             else
     48             {
     49                 fail[next[root][i]] = root;
     50                 Q.push(next[root][i]);
     51             }
     52         while( !Q.empty() )
     53         {
     54             int now = Q.front();
     55             Q.pop();
     56             for(int i = 0;i < 26;i++)
     57                 if(next[now][i] == -1)
     58                     next[now][i] = next[fail[now]][i];
     59                 else
     60                 {
     61                     fail[next[now][i]]=next[fail[now]][i];
     62                     Q.push(next[now][i]);
     63                 }
     64         }
     65     }
     66     int query(char buf[])
     67     {
     68         int len = strlen(buf);
     69         int now = root;
     70         int res = 0;
     71         for(int i = 0;i < len;i++)
     72         {
     73             now = next[now][buf[i]-'a'];
     74             int temp = now;
     75             while( temp != root )
     76             {
     77                 res += end[temp];
     78                 end[temp] = 0;
     79                 temp = fail[temp];
     80             }
     81         }
     82         return res;
     83     }
     84     void debug()
     85     {
     86         for(int i = 0;i < L;i++)
     87         {
     88             printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
     89             for(int j = 0;j < 26;j++)
     90                 printf("%2d",next[i][j]);
     91             printf("]
    ");
     92         }
     93     }
     94 };
     95 char buf[1000010];
     96 Trie ac;
     97 int main()
     98 {
     99     int T;
    100     int n;
    101     scanf("%d",&T);
    102     while( T-- )
    103     {
    104         scanf("%d",&n);
    105         ac.init();
    106         for(int i = 0;i < n;i++)
    107         {
    108             scanf("%s",buf);
    109             ac.insert(buf);
    110         }
    111         ac.build();
    112         scanf("%s",buf);
    113         printf("%d
    ",ac.query(buf));
    114     }
    115     return 0;
    116 }

    AC代码:

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<vector>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    const int N = 26;
    const int MAXN = 500000 + 10;
    struct node
    {
        int next[MAXN][N], fail[MAXN], endd[MAXN];
        int root, l;
        int newnode()
        {
            for (int i = 0; i < N; i++)
                next[l][i] = 0;
            endd[l] = fail[l++] = 0;
            return l - 1;
        }
        void init()
        {
            l = 0;
            root = newnode();
        }
        void Insert(char s[])
        {
            int len = strlen(s);
            int now = root;
            for (int i = 0; i < len; i++)
            {
                if (next[now][s[i] - 'a'] == 0)
                    next[now][s[i] - 'a'] = newnode();
                now = next[now][s[i] - 'a'];
            }
            endd[now]++;
        }
        void build()
        {
            queue<int>qu;
            int now = root;
            for (int i = 0; i < N; i++)
            {
                if (next[root][i])
                    qu.push(next[root][i]);
            }
            while (!qu.empty())
            {
                now = qu.front();
                qu.pop();
                for (int i = 0; i < N; i++)
                {
                    if (!next[now][i])
                        next[now][i] = next[fail[now]][i];
                    else
                    {
                        fail[next[now][i]] = next[fail[now]][i];
                        qu.push(next[now][i]);
                    }
                }
            }
        }
        int query(char s[])
        {
            int len = strlen(s);
            int now = root;
            int ret = 0;
            for (int i = 0; i < len; i++)
            {
                now = next[now][s[i] - 'a'];
                int tmp = now;
                while (tmp != root)
                {
                    ret += endd[tmp];
                    endd[tmp] = 0;
                    tmp = fail[tmp];
                }
            }
            return ret;
        }
    };
    node Aho;
    int T, n;
    char buf[MAXN], str[MAXN * 2];
    int main()
    {
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d", &n);
            Aho.init();
            for (int i = 0; i < n; i++)
            {
                scanf("%s", buf);
                Aho.Insert(buf);
            }
            Aho.build();
            scanf("%s", str);
            int ans = Aho.query(str);
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    Perl如何安装新模块/包
    Perl入门(二)Perl的流程控制
    Perl入门(一)Perl的基本类型及运算符
    Struts2表单数据接收方式
    Struts2 自定义拦截器时Action无法接收到参数
    深入理解Java闭包概念
    Centos 7.2 Jenkins+Ansible+Gitlab 部署maven项目
    Centos 7.2 Jenkins+Ansible+Gitlab 基础配置
    CentOS 7.2 搭建Jenkins
    Linux系统上安装配置MAVEN
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12543159.html
Copyright © 2020-2023  润新知