Keywords Search 【HDU - 2222】【AC自动机模板】

版权声明:https://blog.csdn.net/qq_41730082 https://blog.csdn.net/qq_41730082/article/details/86551817

题目链接


  学习AC自动机的第一道题(可能跟广大学友是一样的),让我知道了什么是AC自动机。

  具体讲一下吧,它就是用来求多串匹配的(而KMP只是求单串匹配的,相当于是在KMP上做了优化)。之后,就是怎么构造AC自动机了,知道它就是在一棵字典树上做文章,我们先对所要查询的字符串作字典树的建立,并且,在每个字符串的尾,也就是每个字符串的尾部在字典树上的值附上"+1",若是能查到这一步,就说明是可以取的一个(或多个完整的单词),然后,我们就可以去拿到它了。

  与KMP一样,它也是需要关系传递的,那么怎么做到传递关系?就是要写一个KMP中的next[]数组一样作用的指针了,这里就叫做fail指针吧,其意义就如同它的名字一样,若是下一步匹配失败,我们可以跳转到哪个相同的点继续判断是一个道理的,但是,这个指针只能跳转到一个更浅的地方去,并且还要保证相同的后缀。

  求fail指针的方法倒也不难,我们可以用一个BFS的思想再带上KMP思想可以合并得到,这样就能有AC自动机的fail指针了。我们利用BFS是为了深度的传递,不能传递到更高深度去,只能向浅的地方去,然后,我们对出队的节点temp,考虑它的后面的26个next[]情况,如果它是有next[]的,我们就对它的下一个节点去找有没有匹配的,就利用再来个新的指针p去查询,这个指针是出队节点的fail指向,于是,若是p->next[i]不为空的时候,就是第一个找到的时候了,那么直接给temp->next[i]->fail = p->next[i];即可,不然,就是直接还到root节点。接下来,再对temp->next[i]入队,我们继续去查询就是了。

  最后,就是索要答案的时候了,我们对模式串,去查询它有多少个单词的覆盖,首先,跟KMP一样,若是目前查到的节点不是虚构的root,就是说前面有匹配的时候,我们得让它的下一个节点也匹配上,那么就是若p->next[x] == NULL;我们就可以去p = p->fail;然后,以此类推,直到找到符合条件的要求的点,或者是空的点(也就是虚假存在的root)。以此,我们不断的去查询,查询完的点赋为"-1"(表示取过了),然后在此之前,取它的值,然后再去取所有它的fail的值,因为既然该数可以,它的fail都只是它的后缀,说明也是可以的,直接取了就是了。最后,就能得到的匹配的数目。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e6 + 7;
int N, ans;
char sss[55], las[maxN];
struct node
{
    node *next[26];
    node *fail;
    int sum;
};
node *root, *new_node;
void update(char *s)
{
    node *temp = root;
    int len = (int)strlen(s);
    for(int i=0; i<len; i++)
    {
        int x = s[i] - 'a';
        if(temp->next[x] == NULL)
        {
            new_node = (node *)malloc(sizeof(node));
            for(int j=0; j<26; j++) new_node->next[j] = NULL;
            new_node->sum = 0;  new_node->fail = NULL;
            temp->next[x] = new_node;
        }
        temp = temp->next[x];
    }
    temp->sum++;
}
queue<node *> Q;
void build_fail()
{
    Q.push(root);
    node *p, *temp;
    while(!Q.empty())
    {
        temp = Q.front();   Q.pop();
        for(int i=0; i<26; i++)
        {
            if(temp->next[i])
            {
                if(temp == root) temp->next[i]->fail = root;
                else
                {
                    p = temp->fail;
                    while(p)
                    {
                        if(p->next[i])
                        {
                            temp->next[i]->fail = p->next[i];
                            break;
                        }
                        p = p->fail;
                    }
                    if(p == NULL) temp->next[i]->fail = root;
                }
                Q.push(temp->next[i]);
            }
        }
    }
}
void AC_auto(char *s)
{
    node *p = root;
    int len = (int)strlen(s);
    for(int i=0; i<len; i++)
    {
        int x = s[i] - 'a';
        while(p != root && !p->next[x]) p = p->fail;
        p = p->next[x];
        if(!p) p = root;
        node *temp = p;
        while(temp != root && temp->sum >= 0)
        {
            ans += temp->sum;
            temp->sum = -1;
            temp = temp->fail;
        }
    }
}
inline void init()
{
    root = (node * )malloc(sizeof(node));
    for(int i=0; i<26; i++) root->next[i] = NULL;
    root->fail = NULL;
    root->sum = 0;
    ans = 0;
    while(!Q.empty()) Q.pop();
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        init();
        scanf("%d", &N);
        for(int i=1; i<=N; i++)
        {
            scanf("%s", sss);
            update(sss);
        }
        scanf("%s", las);
        build_fail();
        AC_auto(las);
        printf("%d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/86551817