【AC自动机】HDU2222Keywords Search

来源:互联网 发布:串口助手软件下载 编辑:程序博客网 时间:2024/06/05 03:24

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222

这个题目刚开始还不会,但是轮到了我给我同学讲课,之前就有看过,一直都没懂。就唯一的知道要会AC自动机,就得先会KMP和字典树。于是我就在杭电上挂了这题,默默的刷着KMP和字典树。突然要我讲课,没办法,就赶紧赶紧的临时在认真的看,分析,最后赶鸭子上架,懵懵懂懂的就上去讲了。讲着讲着发现这个模板我就这样理解了。。。哈哈,真的让我明白,你能做题,不一定能讲清楚一道题,当你能讲清楚一道题,说明你弄懂了这道题。嘿嘿。。。

我是看到这两个博客,学过来的,代码也是综合了一下。

链接:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

          http://blog.csdn.net/hnust_xiehonghao/article/details/9130539

#include<iostream>#include<string>#include<cstring>#include<cstdio>#include<queue>using namespace std;const int N=26;char str[1000005];char s[55];struct node{    node *fail;    node *next[N];    int cnt;    node(){        fail=NULL;        cnt=0;        memset(next,0,sizeof(next));    }};node *p,*temp,*head;void Insert(char s[])           //  建立字典树;{    p=head;    int i=0,id;    while(s[i]){        id=s[i++]-'a';        if(p->next[id]==NULL) p->next[id]=new node();        p=p->next[id];    }    p->cnt++;}void get_fail()             //  BFS构造fail指针;{    node *son;              //  保存子节点;    p=head;    queue<struct node *>q;          //  用队列BFS;    q.push(p);    while(!q.empty()){        temp=q.front();        q.pop();        for(int i=0;i<26;i++){            son=temp->next[i];            if(son!=NULL){                      //  子节点不为空,说明存在该字母;                if(temp==head) son->fail=head;  //  如果子节点的父节点为head,那么fail指针指向head;                else{                    p=temp->fail;               //  p等于当前son的父节点的fail指针;                    while(p){                        if(p->next[i]){         //  如果存在该字母,说明p->next[i]链前面出现的字母也与之匹配;                            son->fail=p->next[i];                            break;                        }                        p=p->fail;                    }                    if(!p) son->fail=head;                }                q.push(son);            }        }    }}int Query()     //  遍历;{    int i=0,ans=0;    p=head;    while(str[i]){        int id=str[i++]-'a';        while( p->next[id]==NULL && p!=head) p=p->fail;     //  当p的子节点不存在,且p不是head的节点时,(因为这种情况当前位置p后面是不会有匹配的字母了)p=p->fail;        p=p->next[id];        if(!p) p=head;          //  如果p为NULL,那么说明该字母开头的单词匹配失败了;        temp=p;        while(temp!=head && temp->cnt!=-1){     //  当temp存在时,且没有被计算过时,进入while循环;            ans+=temp->cnt;            temp->cnt=-1;            temp=temp->fail;        //  访问下一个匹配位置;        }    }    return ans;}int main(){    int t,n;    scanf("%d",&t);    while(t--){        head=new node();        scanf("%d",&n);        getchar();        while(n--){            gets(s);            Insert(s);        }        get_fail();        scanf("%s",str);        printf("%d\n",Query());    }    return 0;}


0 0
原创粉丝点击