Aho-Corasick 多模式匹配算法

 

核心思想简介

KMP算法一样, AC自动机在匹配时如果当前字符匹配失败,那么利用fail指针进行跳转。由此可知如果跳转,跳转到的串的前缀,必为跳转前的模式串的后缀。由此可知,跳转的新位置的深度一定小于跳之前的节点。所以我们可以利用 bfs在 Trie上面进行 fail指针的求解。

 

设这个节点上的字母为x,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为x的节点。然后把当前节点的失败指针指向那个字符也为x的儿子。如果一直走到了root都没找到,那就把失败指针指向root。

给两个经典的图:

计算Trie的失败指针

参考博客:http://www.cnblogs.com/xudong-bupt/p/3433506.html

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16403

code:

#include <iostream>
#include <cstdio>
#include <queue>
#include <stdlib.h>
#include <memory.h>
#define maxn 1000010
#define maxnode 500050
#define sigma_size 26
using namespace std;
char P[maxn],str[55];
int f[maxnode];
int last[maxnode],val[maxnode],has[maxnode];
int ch[maxnode][sigma_size],sz;
void init()
{
    sz=1;last[0]=val[maxnode]=0;
    memset(ch[0],0,sizeof ch[0]);
}
int indx(char c){return c-'a';}
void insert(char *s)
{
    int u=0,n=strlen(s);
    for(int i=0;i<n;i++)
    {
        int c = indx(s[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof ch[sz]);
            val[sz]=0;
            ch[u][c]=sz++;
        }
        u=ch[u][c];
    }
    ++val[u];
}
void getfile()
{
    queue<int>Q;
    f[0]=0;
    for(int c=0; c<sigma_size; c++){
        int u = ch[0][c];
        if(u){
            f[u]=0;Q.push(u);last[u]=0;
        }
    }
    while(!Q.empty()){
        int r = Q.front();Q.pop();
        for(int c = 0 ; c < sigma_size ; c++)
        {
            int u = ch[r][c];
            if(!u)continue;
            Q.push(u);
            int v = f[r];
            while(v&&!ch[v][c])v=f[v];
            f[u] = ch[v][c];
            last[u]=val[f[u]]?f[u]:last[f[u]];
        }
    }
}
void print(int t)
{
    if(t){
        has[t]=1;
        print(last[t]);
    }
}
int find(char *s)
{
    memset(has,0,sizeof has);
    int n=strlen(s),j=0;
    for(int i = 0; i< n;i++)
    {
        int c=indx(s[i]);
        while(j&&!ch[j][c])j=f[j];
        j=ch[j][c];
        if(val[j])print(j);
        else  print(last[j]);
    }
    int ans=0;
    for(int i=0;i<sz;i++)if(has[i])ans+=val[i];
    return ans;
}
int main()
{
//    freopen("in.txt","r",stdin);
    int T,n;scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%s",str);
            insert(str);
        }
        getfile();
        scanf("%s",P);
        printf("%d\n",find(P));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值