洛谷-P3808-AC自动机(模板)

链接:

https://www.luogu.org/problem/P3808

题意:

给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

思路:

模板,

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
//#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
#include <string>
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#define MINF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MAXN = 2e6+10;

struct Trie
{
    int Next[26];
    int End;
    int Fail;
    void Init()
    {
        memset(Next, 0, sizeof(Next));
        End = Fail = 0;
    }
}trie[MAXN];
int cnt, n;
char s[MAXN];

void Insert(char *t)
{
    int len = strlen(t);
    int p = 0;
    for (int i = 0;i < len;i++)
    {
        if (trie[p].Next[t[i]-'a'] == 0)
        {
            trie[p].Next[t[i]-'a'] = ++cnt;
            trie[cnt].Init();
        }
        p = trie[p].Next[t[i]-'a'];
    }
    trie[p].End++;
}

void BuildAC()
{
    queue<int> que;
    for (int i = 0;i < 26;i++)
    {
        if (trie[0].Next[i] != 0)
            que.push(trie[0].Next[i]);
    }
    while (!que.empty())
    {
        int u = que.front();
        que.pop();
        for (int i = 0;i < 26;i++)
        {
            if (trie[u].Next[i])
            {
                trie[trie[u].Next[i]].Fail = trie[trie[u].Fail].Next[i];
                que.push(trie[u].Next[i]);
            }
            else
                trie[u].Next[i] = trie[trie[u].Fail].Next[i];
                //压缩路径, 没有的点直接指向别的节点, 减少向上找的时间
        }
    }
}

int Query(char *qs)
{
    int len = strlen(qs);
    int p = 0, ans = 0;
    for (int i = 0;i < len;i++)
    {
        p = trie[p].Next[qs[i]-'a'];
        for (int j = p;j != 0 && trie[j].End != -1;j = trie[j].Fail)
        {
            //将所有能出现的匹配都跑一遍, 同时处理防止多跑.
            ans += trie[j].End;
            trie[j].End = -1;
        }
    }
    return ans;
}

int main()
{
    cnt = 0;
    scanf("%d", &n);
    trie[0].Init();
    for (int i = 1;i <= n;i++)
    {
        scanf("%s", s);
        Insert(s);
    }
    BuildAC();
    scanf("%s", s);
    printf("%d\n", Query(s));

    return 0;
}
posted @ 2019-09-29 14:27  YDDDD  阅读(98)  评论(0编辑  收藏  举报