码迷,mamicode.com
首页 > 其他好文 > 详细

AC自动机 HDU2222

时间:2020-03-21 23:30:15      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:%s   href   and   pop   namespace   存在   end   icp   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/

 

代码如下:(这道题时间卡的特别严格)

先附上时间被卡的代码,手写了一个,竟被卡掉:

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned int ui;
 4 typedef long long ll;
 5 typedef unsigned long long ull;
 6 #define pf printf
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 #define prime1 1e9+7
 9 #define prime2 1e9+9
10 #define pi 3.14159265
11 #define lson l,mid,rt<<1
12 #define rson mid+1,r,rt<<1|1
13 #define scand(x) scanf("%llf",&x) 
14 #define f(i,a,b) for(int i=a;i<=b;i++)
15 #define scan(a) scanf("%d",&a)
16 #define dbg(args) cout<<#args<<":"<<args<<endl;
17 #define inf 0x3f3f3f3f
18 const int maxn=5e5+10;
19 int n,m,t,tot=0;
20 char s[maxn];
21 int trie[maxn][26],fail[maxn],cnt[maxn];
22 void insert(char* s)
23 {
24     int rt=0,len=strlen(s);
25     f(i,0,len-1)
26     {
27         char c=s[i]-a;
28         if(!trie[rt][c])trie[rt][c]=++tot;
29         rt=trie[rt][c];
30     }
31     cnt[rt]++;//标记单词的尾部 
32 }
33 void getfail()
34 {
35     queue<int>q;
36     f(i,0,25)
37     {
38         if(trie[0][i])
39         {
40             q.push(trie[0][i]);//第一层结点入队 
41             fail[trie[0][i]]=0;
42         }
43         //fail[now]    ->当前节点now的失败指针指向的地方
44         //tire[now][i] -> 下一个字母为i+‘a‘的节点的下标为tire[now][i]
45         while(!q.empty())
46         {
47             int cur=q.front();
48             q.pop();
49             f(i,0,25)
50             {
51                 if(trie[cur][i])
52                 {
53                     fail[trie[cur][i]]=trie[fail[cur]][i];
54                     q.push(trie[cur][i]);
55                 }
56                 else trie[cur][i]=trie[fail[cur]][i];
57             }
58         }
59     }
60 }
61 int query(char* s)
62 {
63     int len=strlen(s);
64     int now=0,ans=0;
65     f(i,0,len-1)
66     {
67         now=trie[now][s[i]-a];
68         for(int j=now;j&&cnt[j]!=-1;j=fail[j])
69         {
70             ans+=cnt[j];
71             cnt[j]=-1;//检查过的点就标记为已知,防止多次检查 
72         }
73     }
74     return ans;
75 }
76 int main()
77 {
78     //freopen("input.txt","r",stdin);
79     //freopen("output.txt","w",stdout);
80     std::ios::sync_with_stdio(false);
81     scan(t);
82     while(t--)
83     {
84         f(i,0,maxn-1)cnt[i]=0,fail[i]=0;
85         f(i,0,maxn-1)
86         f(j,0,25)trie[i][j]=0;
87         tot=0;
88         scan(n);
89         f(i,1,n)
90         {
91             scanf("%s",&s);
92             insert(s);
93         }
94         getfail();
95         scanf("%s",&s);
96         pf("%d\n",query(s));
97     }
98  } 

 

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;
}

 

AC自动机 HDU2222

标签:%s   href   and   pop   namespace   存在   end   icp   hdu2222   

原文地址:https://www.cnblogs.com/randy-lo/p/12543159.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!