Keywords Search

来源:互联网 发布:双十一实时数据直播 编辑:程序博客网 时间:2024/06/03 19:52

描述

In the modern time, Search engine came into the life of everybody like Google, Baidu, etc. Wiskey also wants to bring this feature to his image retrieval system. Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched. To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match.

输入

First line will contain one integer means how many cases will follow by. Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000) Each keyword will only contains characters 'a'-'z', and the length will be not longer than 50. The last line is the description, and the length will be not longer than 1000000.

输出

Print how many keywords are contained in the description.

样例输入

1
5
she
he
say
shr
her
yasherhs

样例输出

3

AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。今天刚刚才接触,这个题算是模版题把,听说还有很多可以优化的地方,这几天好好搞一下

 

#include<iostream>#include<cstring>#include<cstdio>#define M 26using namespace std;struct node{    node *fail;//失败指针    node *next[M];//每个节点的个子节点(26个字母)    int count;//是否为该单词的最后一个节点    node(){        fail=NULL;        count=0;        memset(next,NULL,sizeof(next));    }}*q[500001];//建立q队列,方便bfs构造失败指针char word[5000];//输入的单词char str[1000001];//主串,模式串int head,tail;//队列的头指针和尾指针void insert(char *str,node *root)//构建树,str为单词,而root为构建的树根{    node *p = root;//新建一个p指针,令他指向树根    int i=0,index;//i用来指向单词的单个字母(即为字符串下标)                  //index用来指向next[M]的26个位置(即为字母位置)    while(str[i])    {        index=str[i]-'a';//str[i]-'a'就是当前str[i]在26个字母顺序的位子        if(p->next[index]==NULL)//判如果前字母位置为空,就在当前字母位置创建一个节点            p->next[index]  = new node();            p=p->next[index];//每次p都要往下走        i++;    }    p->count++;  //在单词的最后一个节点count++,代表一个单词}void build_ac(node *root){    int i;    root->fail=NULL;//首先树根的失败指针为空    q[head++]=root;//队列指向树根    while(head!=tail)  //队列  头!=尾    {        node *temp = q[tail++];//新建temp指向队列的尾部        node *p=NULL;   //新建p指针并初始化为空        for(i=0;i<26;i++){            if(temp->next[i]!=NULL){//如果当前字母存在                if(temp==root)//当前temp指向树根                    temp->next[i]->fail=root;//则当前字母的失败指针指向树根                else{             //否则                    p=temp->fail;//p指向temp的失败指针                    while(p!=NULL){                        if(p->next[i]!=NULL){//只要p->next[i]不为空                                             //temp的失败指针指向p->next[i];                                             //同时跳出循环                            temp->next[i]->fail=p->next[i];                            break;                        }                        p=p->fail;                    }                    if(p==NULL)//如果P走到了最后(即p指向了NULL)                        temp->next[i]->fail=root;//temp的失败指针指向树根(root)                }                q[head++]=temp->next[i];//把temp的next[i]赋给队列,head++            }        }    }}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;//找父亲节点的失败指针        p=p->next[index];        p=(p==NULL)?root:p;//如果为空就指向根节点        node *temp=p;        while(temp!=root && temp->count!=-1){            cnt+=temp->count;            temp->count=-1;  //count值设置为-1,表示改单词已经出现过了,防止重复计数            temp=temp->fail;        }        i++;    }    return cnt;}int main(){    int t,n;   scanf("%d",&t);   // cin>>t;    while(t--)    {        node *root = new node();//建立树根        head=tail=0;//队列头尾赋0        scanf("%d",&n);        getchar();        for(int i=0;i<n;i++){            gets(word);            insert(word,root);        }       scanf("%s",&str);        build_ac(root);       printf("%d\n",query(root));    }    return 0;} 


 

 

原创粉丝点击