hdu 2222 Keywords Search--AC自动机

/**
*AC自动机就是给当前串找一个有后续的末端相同的串
*当查找不成功时转向他的失败指针处
*转向时总是抛弃掉几个前段的字符
*/
/*
题意:
给一些单词和一个字符串  求字符串中单词出现的次数和   单词可以有重叠部分
*/
#include <iostream> 
using namespace std; 
  
const int kind = 26; 
struct node{  
    node *fail;       //失败指针
    node *next[kind]; //Tire每个节点的26个子节点(最多26个字母)
    int count;        //是否为该单词的最后一个节点
    node(){           //构造函数初始化
        fail=NULL; 
        count=0; 
        memset(next,NULL,sizeof(next)); 
    } 
}*q[500001];          //队列,方便用于bfs构造失败指针
char keyword[51];     //输入的单词
char str[1000001];    //模式串
int head,tail;        //队列的头尾指针
  
void insert(char *str,node *root){ 
    node *p=root; 
    int i=0,index;  
    while(str[i]){ 
        index=str[i]-'a'; 
        if(p->next[index]==NULL) p->next[index]=new node();  
        p=p->next[index];
        i++;
    } 
    p->count++;//初始化为0,++后为1,表示是一个单词的结尾
} 
void build_ac_automation(node *root)
{
    int i;
    root->fail=NULL; 
    q[head++]=root; 
    while(head!=tail)
	{ 
        node *temp=q[tail++];//拿到一个节点
        node *p=NULL; 
        for(i=0;i<26;i++)
		{ 
            if(temp->next[i]!=NULL)//若其i孩子非空
			{ 
                if(temp==root) //他自己是头,其孩子的失败指针指向头
					temp->next[i]->fail=root;                 
                else{ //普通节点
                    p=temp->fail; //指向自己的失败指针
                    while(p!=NULL)
					{  
                        if(p->next[i]!=NULL)//失败指针有i孩子
						{ 
                            temp->next[i]->fail=p->next[i]; //当前节点的i孩子的失败指针指向失败指针的i孩子,然后跳出
                            break; 
                        } 
                        p=p->fail; //继续找失败指针
                    } 
                    if(p==NULL) //若失败指针为空
						temp->next[i]->fail=root; //当前节点的i孩子的失败指针指向头
                } 
                q[head++]=temp->next[i];  //进去的都是定义过失败指针的,故此过程是给其孩子定义失败指针
            } 
        }   
    } 
} 
int query(node *root)
{ 
    int i=0,cnt=0,index,len=strlen(str); 
    node *p=root;  
    while(str[i])
	{  
        index=str[i]-'a';  //计算孩子的位置
        while(p->next[index]==NULL && p!=root) 
			p=p->fail; //若没有i孩子节点,通过失败指针找与这之前相同的有i孩子的节点
        p=p->next[index]; //指向其i孩子
        p=(p==NULL)?root:p; 
        node *temp=p; 
        while(temp!=root && temp->count!=-1)
		{ 
            cnt+=temp->count; 
            temp->count=-1; 
            temp=temp->fail; 
        } 
        i++;                 
    }    
    return cnt; 
} 
int main(){ 
    int n,t; 
    scanf("%d",&t); 
    while(t--){  
        head=tail=0; 
        node *root=new node(); 
        scanf("%d",&n); 
        getchar(); 
        while(n--){ 
            gets(keyword); 
            insert(keyword,root); 
        } 
        build_ac_automation(root); 
        scanf("%s",str); 
        printf("%d\n",query(root));  
    } 
    return 0; 
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值