zoukankan      html  css  js  c++  java
  • HDU 2222 Keywords Search(AC自动机模板题)

    原题大意:原题链接

    先给定T个单词,然后给定一个字符串,查询该字符串中包含多少个给定的单词

    解题思路:AC自动机模板题

    参考链接:哔哩哔哩算法讲堂

    WA版本

    注意:因为输入的单词可能有重复,那么Insert()函数中p->id=id;语句中p->id会被覆盖,在Query()函数中会一次性全部被清零,导致不能查询重复单词,以至于结果res错误.

    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int T,n;
    char word[60],str[1000010];
    struct TrieNode
    {
        int id;
        TrieNode *next[26],*fail;
        TrieNode(){
            id=0,fail=NULL;
            memset(next,0,sizeof(next));
        }
    }*root;
    
    void Insert(char *word,int id)
    {
        TrieNode *p=root;
        int len=strlen(word);
        for(int i=0;i<len;i++){
            if(!p->next[word[i]-'a']) 
                p->next[word[i]-'a']=new TrieNode();
            p=p->next[word[i]-'a'];
        }
        p->id=id; 
    }
    void Build_AC()
    {
        TrieNode *p,*next;
        queue<TrieNode* > que;
        que.push(root);
        while (!que.empty()){
            p=que.front();
            que.pop();
            for(int i=0;i<26;i++){
                if(p->next[i]){
                    if(p==root) p->next[i]->fail=root;
                    else{
                        TrieNode *temp=p->fail;
                        while(temp){
                             if(temp->next[i]){//temp始终代表next[i]的爸爸,有next[i]这个儿子 
                                 p->next[i]->fail=temp->next[i];
                                break;//寻找最长后缀 
                            }
                            temp=temp->fail;
                        }
                        if(!temp) p->next[i]->fail=root;
                    }
                    que.push(p->next[i]);
                }
            }
        }
    }
    int Query()
    {
        TrieNode *p=root;
        int res=0,len=strlen(str);
        for(int i=0;str[i];i++){
            int jd=str[i]-'a';
            while(!p->next[jd]&&p!=root)//当p为根节点时失配边仍根节点会死循环 
                  p=p->fail;
            p=p->next[jd];
            if(!p) p=root;
            TrieNode *temp=p;
            while(temp!=root&&temp->id){
                res++;
                temp->id=0;
                temp=temp->fail;
            }
        }
        return res;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--){
            root=new TrieNode();
            scanf("%d
    ",&n);
            for(int i=1;i<=n;i++){
                gets(word);
                Insert(word,i);
            }
            Build_AC();
            scanf("%s",str);
            printf("%d
    ",Query());
        }
        return 0;
    }

    AC版本

    #include<queue>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int T,n;
    char word[60],str[1000010];
    struct TrieNode
    {
        int id;
        TrieNode *next[26],*fail;
        TrieNode(){
            id=0,fail=NULL;
            memset(next,0,sizeof(next));
        }
    }*root;
    
    void Insert(char *word)
    {
        TrieNode *p=root;
        int len=strlen(word);
        for(int i=0;i<len;i++){
            if(!p->next[word[i]-'a']) 
                p->next[word[i]-'a']=new TrieNode();
            p=p->next[word[i]-'a'];
        }
        p->id++;
    }
    void Build_AC()
    {
        TrieNode *p,*next;
        queue<TrieNode* > que;
        que.push(root);
        while (!que.empty()){
            p=que.front();
            que.pop();
            for(int i=0;i<26;i++){
                if(p->next[i]){
                    if(p==root) p->next[i]->fail=root;
                    else{
                        TrieNode *temp=p->fail;
                        while(temp){
                             if(temp->next[i]){//temp始终代表next[i]的爸爸,有next[i]这个儿子 
                                 p->next[i]->fail=temp->next[i];
                                break;//寻找最长后缀 
                            }
                            temp=temp->fail;
                        }
                        if(!temp) p->next[i]->fail=root;
                    }
                    que.push(p->next[i]);
                }
            }
        }
    }
    int Query()
    {
        TrieNode *p=root;
        int res=0,len=strlen(str);
        for(int i=0;str[i];i++){
            int jd=str[i]-'a';
            while(!p->next[jd]&&p!=root)//当p为根节点时失配边仍根节点会死循环 
                  p=p->fail;
            p=p->next[jd];
            if(!p) p=root;
            TrieNode *temp=p;
            while(temp!=root&&temp->id!=-1){
                res+=temp->id;
                temp->id=-1;
                temp=temp->fail;
            }
        }
        return res;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--){
            root=new TrieNode();
            scanf("%d
    ",&n);
            for(int i=1;i<=n;i++){
                gets(word);
                Insert(word);
            }
            Build_AC();
            scanf("%s",str);
            printf("%d
    ",Query());
        }
        return 0;
    }
  • 相关阅读:
    冒泡排序
    pdo 单例类
    php 事物处理
    支付宝支付
    反向代理和负载均衡
    execl导出
    网络层
    OSI 7层 TCP/IP 4层 综合5层
    面试总结
    CMD AMD
  • 原文地址:https://www.cnblogs.com/freinds/p/6504687.html
Copyright © 2011-2022 走看看