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

原文地址:https://www.cnblogs.com/GarrettWale/p/11330771.html

时间: 2024-10-06 02:00:10

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

hdu 2222 AC自动机(可做模板)

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 50101    Accepted Submission(s): 16083 Problem Description In the modern time, Search engine came into the life of everybody li

HDOJ 2222 AC自动机

链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 代码: 31 string s, a[51]; 32 int head, tail; 33 34 struct node { 35 node *fail; 36 node *next[26]; 37 int count; 38 node() { 39 fail = NULL; 40 count = 0; 41 rep(i, 0, 26) next[i] = NULL; 42 } 43 }*q[M

HDU 2222 AC自动机模板题

题目: http://acm.hdu.edu.cn/showproblem.php?pid=2222 AC自动机模板题 1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 using namespace std; 5 char key[55]; 6 char des[1111111]; 7 struct node{ 8 node *fail; 9 node *next[26]; 10 int cnt;

POJ 1226后缀数组:求出现或反转后出现在每个字符串中的最长子串

思路:这题是论文里的最后一道练习题了,不过最后一题竟然挺水的. 因为求的是未反转或者反转后,最长公共子串. 刚开始还真不知道怎么构建连接成一个字符串,因为需要有反转嘛! 但是其实挺简单的,把未反转的和反转后的字符串都连起来,中间用未出现过的字符隔开就行了!然后未反转的和反转的在同一组. 二分枚举最长的公共前缀长度,然后统计看看这个最长的长度在不在所有的组里,如果在就符合-- #include<iostream> #include<cstdio> #include<cstrin

hdu 2222 AC自动机(模板题)

<题目链接> 题目大意: 给你一些单词,和一个字符串,问你这个字符串中含有多少个上面的单词. 解题分析: 这是多模匹配问题,如果用KMP的话,对每一个单词,都跑一遍KMP,那么当单词数量非常多的时候,耗时会非常多,所以这里用到了AC自动机,这是一种类似于Trie树的数据结构,但是同时,它也用到了KMP算法中 next数组的思想. 下面是AC自动机指针形式的题解: #include <stdio.h> #include <stdlib.h> #include <st

HDU 2222 ----AC自动机

Problem Description In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.Wiskey also wants to bring this feature to his image retrieval system.Every image have a long description, when users type some keywords to

HDU 2222 AC自动机(模版题)

Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 70290    Accepted Submission(s): 23917 Problem Description In the modern time, Search engine came into the life of everybody lik

hdu 2222 AC自动机学校

#include <iostream>#include <stdio.h>#include <queue>using namespace std;const int maxn=(int)1e6+10;const int maxm=(int)5e5+10;struct trie{ int nxt[maxm][26],fail[maxm],ed[maxm]; int rt,l; int newnod(){ for(int i=0;i<26;i++)nxt[l][i]=

hdu 2222 Keywords Search ac自动机入门

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:有N(N <= 10000)个长度不超过50的模式串和一个长度不超过1e6的文本串.其中模式串可以重复.问有多少文本串在模式串中出现过.(对于相同的模式串次数仍然累加) 思路:ac自动机裸题: KMP是先将文本串进行匹配得到失配边f[];但是并不适用于文本串较长,模式串较多的情况.因为每次查询的时间复杂度为O(n+m).n,m分别为文本串和模式串的长度: ac自动机就是建立在Trie上,