标签:
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 44594    Accepted Submission(s): 14056
 
 
 
1 5 she he say shr her yasherhs
 
3
题意:给定N个字符串,然后是一个文章,问你在文章中有多少个字符串是出现了的,不计算重复
ps:AC自动机,今天才学的,若有所感,很容易,真的,在博客中发表了这个算法的学习。求共同进步。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct node
{
    node *fail,*next[26];//fail:指向同级节点,当匹配失败时跳转,含义为x后缀包含的x同级节点整个串
    int x;
    node()//用来初始化
    {
        fail=NULL;
        x=0;
        for(int i=0;i<26;i++)next[i]=NULL;
    }
}*root;
node *q[500010];
char str[1000010];
void setit(char *ss)//这是构建字典树
{
    int i,j,k,l;
    node *p=root;
    for(i=0;ss[i];i++)
    {
        k=ss[i]-‘a‘;
        if(p->next[k]==NULL)//如果下一个字符无节点
        p->next[k]=new node();//创建并连接在p的后面
        p=p->next[k];
    }
    p->x++;
}
void ac()//AC自动机算法的构建,跟KMP的next
{
    int tail,head;
    tail=head=0;
    q[tail++]=root;//广搜每个节点,这样是按照树的深度一层一层来搜索,fail只会只想当前层以上的点,你懂的。
    while(head!=tail)
    {
        node *p=q[head++];//取出当前点
        for(int i=0;i<26;i++)//遍历26个字符,这里用ascll码表示
        if(p->next[i]!=NULL)//如果存在
        {
            if(p==root)//如果存在于根节点下面也就是第二层
            {
                p->next[i]->fail=root;//默认指向根节点,因为第一个字符都匹配错误,那可定从头开始啊
                q[tail++]=p->next[i];//入队
                continue;
            }
            node *cur=p->fail;//取出查询字符的上一层节点,用cur找它的同级节点
            while(cur!=NULL)//如果是空就结束,因为root的fail我初始化设定是NULL
            {
                if(cur->next[i]!=NULL)//如果找到某个同级节点并且它后面有当前字符
                {
                    p->next[i]->fail=cur->next[i];//把当前字符的fail指针指向同级节点后面的那个字符的位置
                    break;
                }
                cur=cur->fail;
            }//cout<<(p->next[i]==NULL?1:0)<<endl;
            if(cur==NULL)//如果没有找到合适的匹配
            p->next[i]->fail=root;//那么当前字符的fail就指向root根节点
            q[tail++]=p->next[i];//入队
        }
    }
}
int query()//在AC自动机算法处理后的字典树中对字符串进行匹配
{
    int i,j,k,l,sum=0,cur;
    node *p=root;
    for(i=0;str[i];i++)//遍历每一个字符
    {
        cur=str[i]-‘a‘;//取出字符
        while(p->next[cur]==NULL&&p!=root)//如果节点的后面没有当前字符就继续找同级,直到根节点
        p=p->fail;
        if(p->next[cur]!=NULL)p=p->next[cur];//跳向当前字符所在节点,如果没有找到合适,那么p=root,所以判断cur下一层是否有当前字符存在,不存在就继续让p指向root
        node *q=p;//用q替代p来进行操作
        while(q!=root&&q->x!=-1)//查询所有同级节点,直到root或者已经被查询过
        {
            sum+=q->x;//把个数加起来
            q->x=-1;//查询过了就设置断点
            q=q->fail;
        }
    }
    return sum;
}
int main (void)
{
    int t,n,m,i,j,k,l;
    scanf("%d",&t);
    while(t--&&scanf("%d",&n))
    {
        root=new node();
        for(i=0;i<n;i++)
        {
            char ss[55];
            scanf("%s",ss);
            setit(ss);
        }
        ac();//cout<<"A"<<endl;
        scanf("%s",str);
        printf("%d\n",query());
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU--2222--Keywords Search--AC自动机
标签:
原文地址:http://blog.csdn.net/jingdianitnan/article/details/47708811