HDU2222 Keywords Search【AC自动机】

----- 字 符 串 ----- 同时被 2 个专栏收录
18 篇文章 0 订阅
2 篇文章 0 订阅

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2222

 

题目大意:

给你 N 个模式串,和一个文本串。问:文本串中共出现了几个模式串。

 

思路:

这道题是 AC 自动机的基础题目。就是求文本串中出现的模式串个数。用 Val[] 数组来标记模式串。

最后用 ans 累加模式串个数。

 

AC代码:

 

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN = 500010;
const int SIZE = 26;
struct Trie
{   //Next[i][j]表示字典中i节点的字符为j的儿子节点编号
    int Next[MAXN][SIZE];
    int Fail[MAXN]; //失配数组  
    int Val[MAXN];  //标记模式串
    int root,L;     //L为节点编号
    int NewNode()   
    {
        for(int i = 0; i < 26; ++i)
            Next[L][i] = -1;
        Val[L++] = 0;
        return L-1;
    }
    void Init()
    {
        L = 0;
        root = NewNode();
    }
    void Insert(char *Buf)
    {
        int len = strlen(Buf);
        int now = root;
        for(int i = 0; i < len; ++i)
        {
            if(Next[now][Buf[i]-'a'] == -1)
                Next[now][Buf[i]-'a'] = NewNode();
            now = Next[now][Buf[i]-'a'];
        }
        Val[now]++; //在模式串末尾标记
    }
    void Build()    //构造AC自动机
    {
        queue<int> Q;
        Fail[root] = root;
        for(int i = 0; i < 26; ++i)
        {
            if(Next[root][i] == -1)
                Next[root][i] = root;
            else
            {
                Fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        }
        while( !Q.empty() )
        {
            int now = Q.front();
            Q.pop();
            for(int i = 0; i < 26; ++i)
            {
                if(Next[now][i] == -1)
                    Next[now][i] = Next[Fail[now]][i];
                else
                {
                    Fail[Next[now][i]] = Next[Fail[now]][i];
                    Q.push(Next[now][i]);
                }
            }
        }
    }
    int Query(char *Buf)    
    {
        int len = strlen(Buf);
        int now = root;
        int res = 0;    //计算模式串出现个数
        for(int i = 0; i < len; ++i)
        {
            now = Next[now][Buf[i]-'a'];
            int temp = now;
            while(temp != root)
            {
                res += Val[temp];
                Val[temp] = 0;
                temp = Fail[temp];
            }
        }
        return res;
    }
    
//    void Debug()
//    {
//        for(int i = 0; i < L; ++i)
//        {
//            printf("id = %3d,Fail = %3d,Val = %3d,chi = [",i,Fail[i],Val[i]);
//            for(int j = 0; j < 26; ++j)
//                printf("%2d",Next[i][j]);
//            printf("]\n");
//        }
//    }

};
char Buf[MAXN<<1];
Trie AC;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int N;
        scanf("%d",&N);
        AC.Init();
        for(int i = 0; i < N; ++i)
        {
            scanf("%s",Buf);
            AC.Insert(Buf);
        }
        AC.Build();
        scanf("%s",Buf);
        printf("%d\n",AC.Query(Buf));
    }

    return 0;
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值