文章标题 HDU 2222 : Keywords Search (AC自动机模板)

来源:互联网 发布:qq炫舞卡八音软件 编辑:程序博客网 时间:2024/06/18 15:32

题目链接
题意:有n个单词,然后有一个文本串,问有多少个单词出现在文本串中出现,每个单词只技术一次
分析:ac自动机模板题,得注意单词只计数一次。
代码:

#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <queue>using namespace std;const int maxn=500000+10;int n;int ch[maxn][26];//trie中每个点的儿子节点编号int fail[maxn];int last[maxn];//后缀链接:沿着i的失配指针走遇到的下一个单词节点的编号int val[maxn];//点上的标记(比如标记是否是单词节点)int sz;int root;int newnode (){//新节点     memset (ch[sz],0,sizeof (ch[sz]));//将其孩子置为0     val[sz]=0;    return sz++;}void init(){//初始化     sz=0;    root=newnode();}int insert(char *str){//建树     int len=strlen(str);    int now=root;    for (int i=0;i<len;i++){        int c=str[i]-'a';         if (!ch[now][c]){            memset (ch[sz],0,sizeof (ch[sz]));            val[sz] = 0;            ch[now][c] = sz++;        }        now=ch[now][c];    }    val[now]++;    return now;}void getfail(){    queue<int>q;    fail[root]=root;    for (int i=0;i<26;i++){        int u=ch[root][i];        if (u){            fail[u]=0;            last[u]=0;            q.push(u);        }    }    while (!q.empty()){        int now=q.front();q.pop();        for (int i=0;i<26;i++){            int u=ch[now][i];            //u=ch[now][i]就是我们说的当前节点A,now是A的父节点,            //那么fail[now]就相当于我们说的父节点的失败节点C            if (!u){                /*                如果当前节点now没有i这个儿子u,                直接让这个点的第i个儿子u指向now的失败节点的第i个儿子。                因为如果一个串在AC自动机里面走,走到now时要走的下一个节点是i,                now又没有i这个儿子,因此一定会是失配的。                既然失配了,now就要沿着fail指针走,试图去匹配失败节点的第i个儿子。                这里的ch[now][i]=ch[fail[now]][i]就相当于                让他直接去匹配now的失败节点的第i个儿子                */                ch[now][i]=ch[fail[now]][i];            }            else {                //如果当前节点now有i这个儿子u,                //那么u的失败节点显然要指向C(即fail[now])的第i个儿子                fail[u]=ch[fail[now]][i];                last[u]=val[fail[u]]?fail[u]:last[fail[u]];                q.push(u);            }        }    }}int quary(char *str){    int len=strlen(str);    int now=root;    int ans=0;    for (int i=0;i<len;i++){        now=ch[now][str[i]-'a'];        int tmp=now;        if (tmp!=root&&!val[tmp]&&last[tmp]){            tmp=last[tmp];        }        while (tmp!=root&&val[tmp]){            ans+=val[tmp];            val[tmp]=0;            tmp=last[tmp];        }    }    return ans;}char text[1000005];char str[55];int main(){    int t;    scanf("%d",&t);    while (t--){         init();        scanf ("%d",&n);        for (int i=0;i<n;i++){            scanf ("%s",str);            insert (str);        }        getfail();        scanf ("%s",text);        printf ("%d\n",quary(text));    }     return 0; } /*1002cabcdabcde*/
阅读全文
0 0
原创粉丝点击