AC自动机——搜索关键词

限于喜欢 提交于 2020-02-08 18:50:43

搜索关键词

给定 n 个长度不超过 50 的由小写英文字母组成的单词,以及一篇长为 m 的文章。

请问,有多少个单词在文章中出现了。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。

对于每组数据,第一行一个整数 n,接下去 n 行表示 n 个单词,最后一行输入一个字符串,表示文章。

输出格式
对于每组数据,输出一个占一行的整数,表示有多少个单词在文章中出现。

数据范围
1n1041≤n≤10^4,
1m1061≤m≤10^6
输入样例:
1
5
she
he
say
shr
her
yasherhs
输出样例:
3

题解:

第一道ac自动机的题,相对于kmp,ac自动机就是把一维的信息放在了树上来进行统计了。

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+7,S=55,M=1e6+7;
int ne[N*S],con[N*S],tr[N*S][26],cnt;
char str[M];
queue<int> q;
void insert()
{
    int p=0;
    for(int i=0;str[i];i++){
        int t=str[i]-'a';
        if(!tr[p][t]) tr[p][t]=++cnt;
        p=tr[p][t];
    }
    con[p]++;
}
void build()
{
    for(int i=0;i<26;i++){
        if(tr[0][i]) q.push(tr[0][i]);
    }
    while (!q.empty()){
        int t=q.front(); q.pop();
        for(int i=0;i<26;i++){
            int p=tr[t][i];
            if(!p) tr[t][i]=tr[ne[t]][i];//没路建路
            else{
                ne[p]=tr[ne[t]][i];//有路,下次没有匹配到就可以跳回这里
                q.push(p);//当前层节点放入
            }
        }
    }
}
int main()
{
    int t; scanf("%d",&t);
    while(t--){
        cnt=0;
        memset(tr,0,sizeof tr);
        memset(con,0,sizeof con);
        memset(ne,0,sizeof ne);
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",str);
            insert();
        }
        scanf("%s",str);
        build();
        int res=0;
        for(int i=0,j=0;str[i];i++){
            int t=str[i]-'a';
            j=tr[j][t];
            int p=j;
            while(p){
                res+=con[p];
                con[p]=0;
                p=ne[p];
            }
        }
        cout<<res<<endl;
    }
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!