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;
}
posted @ 2019-08-10 10:40  Garrett_Wale  阅读(107)  评论(0编辑  收藏  举报