HDOJ-2222(AC自动机+求有多少个模板串出现在文本串中)

Posted garrettwale

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDOJ-2222(AC自动机+求有多少个模板串出现在文本串中)相关的知识,希望对你有一定的参考价值。

Keywords Search

HDOJ-2222

  • 本文是AC自动机的模板题,主要是利用自动机求有多少个模板出现在文本串中
  • 由于有多组输入,所以每组开始的时候需要正确的初始化,为了不出错
  • 由于题目的要求是有多少字符串出现过,而不是出现过多少次,所以出现过的模板串就不能再计数了,所欲需要置-1.
  • 不要忘记build函数应该在insert函数之后调用,也不要忘记调用。
//AC自动机,复杂度为O(|t|+m),t表示文本串的长度,m表示模板串的个数
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1E6+6;
int n;
int tree[N][26];//trie树上的结点,tree[i][j]表示i结点后面加一条j的边所对应的的结点
int total;//总结点
int num[N];//num[i]表示结点i上对应的模板串的个数
int fail[N];//失配指针,fail[i]指向所有模板串的前缀中匹配当前状态的最长后缀,指向的是最长后缀(和当前状态的后缀是匹配的,即相同,不过要最长)
queue<int> q;
int idx(char c)//用来求字符c对应的编号(0-25)
    return c-'a';

void insert(string s)//类似于后缀树的插入一个模板串
    int u=0;
    for(int i=0;i<s.length();i++)
        if(!tree[u][idx(s[i])])
            tree[u][idx(s[i])]=++total;
        u=tree[u][idx(s[i])];
    
    num[u]++;

void build()//建AC自动机以及fail数组
    for(int i=0;i<26;i++)
        if(tree[0][i])
            q.push(tree[0][i]);
    
    while(!q.empty())
        int u=q.front();
        q.pop();
        for(int i=0;i<26;i++)
            if(tree[u][i])//如果结点u连的边为i对应的结点存在,则将这个存在的结点的fail指针指向父节点失配指针指向的结点的连的边为i所对应的的结点
                fail[tree[u][i]]=tree[fail[u]][i];
                q.push(tree[u][i]);
            else//类似于状态压缩,不至于每次fail指针跳转很多次,只需每次跳转一次,相当于构建了图
                tree[u][i]=tree[fail[u]][i];
            
        
    

int query(string t)//s为要查找的文本串
    int u=0;
    int res=0;//记录答案,所有的模板串共出现了多少次
    for(int i=0;i<t.length();i++)
        u=tree[u][idx(t[i])];
        for(int j=u;j>0&&num[j]!=-1;)
            res+=num[j];
            num[j]=-1;
            j=fail[j];
        
    
    return res;

int main()
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
        cin>>n;
        while(!q.empty())//清空队列
            q.pop();
        
        memset(fail,0,sizeof(fail));
        memset(num,0,sizeof(num));
        memset(tree,0,sizeof(tree));
        string s;
        for(int i=0;i<n;i++)
            cin>>s;
            insert(s);
        
        build();
        cin>>s;//模板串
        int ans=query(s);
        cout<<ans<<endl;
    
    return 0;

以上是关于HDOJ-2222(AC自动机+求有多少个模板串出现在文本串中)的主要内容,如果未能解决你的问题,请参考以下文章

HDOJ 2222 AC自动机

AC自动机模板题

模板AC自动机

P3808 模板AC自动机(简单版)

模板AC自动机(简单版)

模板AC自动机(简单版)