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("]\n");
 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\n",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\n", ans);
    }
    return 0;
}

 

posted @ 2020-03-21 22:59  WA自动机~  阅读(282)  评论(0编辑  收藏  举报