AC自动机

来源:互联网 发布:jquery post 返回json 编辑:程序博客网 时间:2024/06/05 20:22

今天学习了一下AC自动机,大概流程和KMP算法很像。AC自动机是根据一棵tire树来建出失配数组。接下来的查询过程也比较相似,如果跑到一个点,这个点的danger节点有值,说明这里有一个单词被查询到了。


1.某个单词ins完,danger[x]++

2.用bfs求出失配数组


做(抄)了一道模板题。hdu2222。

给n个单词,一篇文章。问有几个单词出现过。


模板代码:

#include<cstdio>
#include<cstring>
using namespace std;

char s[51],m[1000001];
int T,n,sz,ans;
int a[500001][27],q[500001],point[500001],danger[500001];

void ins()//建立字典树
{
    int x=1,len=strlen(s+1),o;
    for (int i=1;i<=len;++i)
    {
        if (!a[x][o=s[i]-'a'+1]) a[x][o]=++sz;
        x=a[x][o];
    }
    danger[x]++;//出现过的单词在末尾把它记录一下
}

void acmach()//建立AC自动机
{
    int t=0,w=1,now;
    q[0]=1; point[1]=0;//队列实现
    for (;t<w;)
    {
        now=q[t++];
        for (int i=1;i<=26;++i)
        {
            if (!a[now][i]) continue;
            int k=point[now];//连连连
            for (;!a[k][i];k=point[k]);//k是要连的点的父亲
            point[a[now][i]]=a[k][i];
            q[w++]=a[now][i];
        }
    }
}

void solve()
{
    int k=1,len=strlen(m+1);
    for (int i=1;i<=len;++i)
    {
        int t=m[i]-'a'+1;
        for (;!a[k][t];k=point[k]);
        k=a[k][t];
        for (int j=k;j;j=point[j])
        {
            ans+=danger[j];
            danger[j]=0;
        }
    }
    printf("%d\n",ans);
}

int main()
{
    scanf("%d",&T);
    while (T--)
    {
    scanf("%d",&n); sz=1; ans=0;//sz=1,不要写错
    for (int i=1;i<=26;++i) a[0][i]=1; //这里的初始化要注意,把根标号为1
    for (int i=1;i<=n;++i)
    {
        scanf("%s",s+1);
        ins();
    }
    acmach();
    scanf("%s",m+1);
    solve();
    for(int i=1;i<=sz;i++)
        {
            point[i]=danger[i]=0;
            for(int j=1;j<=26;j++)
                a[i][j]=0;
        }
    }
    return 0;
}

原创粉丝点击