HDOJ-2222 (AC + automaton seeking how many templates string appears in the text string)

Keywords Search

HDOJ-2222

  • This article is the template title AC automatic machines, mainly using automaton seeking how many templates appear in the text string
  • Because multiple sets of input, so the start time of each group needs proper initialization, in order not to mistake
  • Since the required number string is subject appeared, instead of how many times occur, so there have been no longer counted template string, the desired needs to be set to -1.
  • Do not forget to build function should be called after the insert function, and do not forget to call.
//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;
}

Guess you like

Origin www.cnblogs.com/GarrettWale/p/11330771.html