• 666 专题五 AC自动机


    Problem A.Keywords Search

    d.n个关键字,1段描述,求描述中出现了多少关键字

    s.

    c.

    /*
    ac自动机模板
    n个关键字,1段描述,求描述中出现了多少关键字
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    struct Trie{
        int next[500010][26],fail[500010],end[500010];
        int root,L;
        int newnode(){
            for(int i=0;i<26;i++)
                next[L][i]=-1;
            end[L++]=0;
            return L-1;
        }
        void init(){
            L=0;
            root=newnode();
        }
        void insert(char buf[]){
            int len=strlen(buf);
            int now=root;
            for(int i=0;i<len;i++){
                if(next[now][buf[i]-'a']==-1)
                    next[now][buf[i]-'a']=newnode();
                now=next[now][buf[i]-'a'];
            }
            end[now]++;
        }
        void build(){
            queue<int>Q;
            fail[root]=root;
            for(int i=0;i<26;i++)
                if(next[root][i]==-1)
                next[root][i]=root;
                else{
                    fail[next[root][i]]=root;
                    Q.push(next[root][i]);
                }
            while(!Q.empty()){
                int now=Q.front();
                Q.pop();
                for(int i=0;i<26;i++)
                    if(next[now][i]==-1)
                        next[now][i]=next[fail[now]][i];
                    else{
                        fail[next[now][i]]=next[fail[now]][i];
                        Q.push(next[now][i]);
                    }
            }
        }
        int query(char buf[]){
            int len=strlen(buf);
            int now=root;
            int res=0;
            for(int i=0;i<len;i++){
                now=next[now][buf[i]-'a'];
                int temp=now;
                while(temp!=root){
                    res+=end[temp];
                    end[temp]=0;
                    temp=fail[temp];
                }
            }
            return res;
        }
        void debug(){
            for(int i=0;i<L;i++){
                printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
                for(int j=0;j<26;j++)
                    printf("%2d",next[i][j]);
                printf("]
    ");
            }
        }
    };
    
    char buf[1000010];
    Trie ac;
    
    int main(){
        int T;
        int n;
        scanf("%d",&T);
        while(T--){
            scanf("%d",&n);
            ac.init();
            for(int i=0;i<n;i++){
                scanf("%s",buf);
                ac.insert(buf);
            }
            ac.build();
            scanf("%s",buf);
            printf("%d
    ",ac.query(buf));
        }
        return 0;
    }
    View Code

    Problem B.病毒侵袭

    d.这题和上题差不多,要输出出现模式串的id,用end记录id就可以了。还有trie树的分支是128的

    s.

    c.

    /*
    ac自动机模板
    n个关键字,1段描述,求描述中出现了多少关键字
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<set>
    using namespace std;
    
    struct Trie{
        int next[510*210][128],fail[510*210],end[510*210];
        int root,L;
        int newnode(){
            for(int i=0;i<128;i++)
                next[L][i]=-1;
            end[L++]=-1;
            return L-1;
        }
        void init(){
            L=0;
            root=newnode();
        }
        void insert(char buf[],int id){
            int len=strlen(buf);
            int now=root;
            for(int i=0;i<len;i++){
                if(next[now][buf[i]]==-1)
                    next[now][buf[i]]=newnode();
                now=next[now][buf[i]];
            }
            end[now]=id;
        }
        void build(){
            queue<int>Q;
            fail[root]=root;
            for(int i=0;i<128;i++)
                if(next[root][i]==-1)
                next[root][i]=root;
                else{
                    fail[next[root][i]]=root;
                    Q.push(next[root][i]);
                }
            while(!Q.empty()){
                int now=Q.front();
                Q.pop();
                for(int i=0;i<128;i++)
                    if(next[now][i]==-1)
                        next[now][i]=next[fail[now]][i];
                    else{
                        fail[next[now][i]]=next[fail[now]][i];
                        Q.push(next[now][i]);
                    }
            }
        }
    
        set<int>myset;
    
        bool query(char buf[],int id){
            myset.clear();
            int len=strlen(buf);
            int now=root;
    
            for(int i=0;i<len;i++){
                now=next[now][buf[i]];
                int temp=now;
                while(temp!=root){
                    if(end[temp]!=-1){
                        myset.insert(end[temp]);
                    }
                    temp=fail[temp];
                }
            }
    
            if(!myset.empty()){
                printf("web %d:",id);
                for(set<int>::iterator it=myset.begin();it!=myset.end();++it){
                    printf(" %d",*it);
                }
                printf("
    ");
                return true;
            }
            return false;
        }
        void debug(){
            for(int i=0;i<L;i++){
                printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
                for(int j=0;j<128;j++)
                    printf("%2d",next[i][j]);
                printf("]
    ");
            }
        }
    };
    
    char buf[10005];
    Trie ac;
    
    int main(){
    
        int N,M;
        int ans;
    
        while(~scanf("%d",&N)){
            ac.init();
    
            for(int i=1;i<=N;++i){
                scanf("%s",buf);
                ac.insert(buf,i);
            }
    
            ac.build();
    
            scanf("%d",&M);
            ans=0;
            for(int i=1;i<=M;++i){
                scanf("%s",buf);
                if(ac.query(buf,i)){
                    ++ans;
                }
            }
    
            printf("total: %d
    ",ans);
    
        }
    
        return 0;
    }
    View Code

    Problem C.病毒侵袭持续中

    d.这题的变化也不大,就是需要输出每个模式串出现的次数,查询的时候使用一个数组进行记录就可以了

    s.

    c.

    /*
    ac自动机模板
    n个关键字,1段描述,求描述中出现了多少关键字
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    
    char str[1024][64];
    
    struct Trie{
        int next[1005*55][26],fail[1005*55],end[1005*55];
        int root,L;
        int newnode(){
            for(int i=0;i<26;i++)
                next[L][i]=-1;
            end[L++]=-1;
            return L-1;
        }
        void init(){
            L=0;
            root=newnode();
        }
        void insert(char buf[],int id){
            int len=strlen(buf);
            int now=root;
            for(int i=0;i<len;i++){
                if(next[now][buf[i]-'A']==-1)
                    next[now][buf[i]-'A']=newnode();
                now=next[now][buf[i]-'A'];
            }
            end[now]=id;
        }
        void build(){
            queue<int>Q;
            fail[root]=root;
            for(int i=0;i<26;i++)
                if(next[root][i]==-1)
                    next[root][i]=root;
                else{
                    fail[next[root][i]]=root;
                    Q.push(next[root][i]);
                }
            while(!Q.empty()){
                int now=Q.front();
                Q.pop();
                for(int i=0;i<26;i++)
                    if(next[now][i]==-1)
                        next[now][i]=next[fail[now]][i];
                    else{
                        fail[next[now][i]]=next[fail[now]][i];
                        Q.push(next[now][i]);
                    }
            }
        }
    
        int sum[1024];
    
        void query(char buf[],int N){
            memset(sum,0,sizeof(sum));
            int len=strlen(buf);
            int now=root;
    
            for(int i=0;i<len;i++){
                if(buf[i]<'A'||buf[i]>'Z'){
                    now=root;//如果用128个来建字典树的话,没有的字符应该是指向root吧?应该是。
                    continue;//(即下面的now=next[now][buf[i]]的值应该是root?)
                    //使用这种判断的开辟26个字符即可,节省空间
                }
                now=next[now][buf[i]-'A'];
                int temp=now;
                while(temp!=root){
                    if(end[temp]!=-1){
                        ++sum[end[temp]];
                    }
    
                    temp=fail[temp];
                }
            }
    
            for(int i=0;i<N;++i){
                if(sum[i]>0){
                    printf("%s: %d
    ",str[i],sum[i]);
                }
            }
        }
        void debug(){
            for(int i=0;i<L;i++){
                printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
                for(int j=0;j<26;j++)
                    printf("%2d",next[i][j]);
                printf("]
    ");
            }
        }
    };
    
    char buf[2000005];
    Trie ac;
    
    int main(){
    
        int N;
    
        while(~scanf("%d",&N)){
            ac.init();
            for(int i=0;i<N;i++){
                scanf("%s",str[i]);
                ac.insert(str[i],i);
            }
            ac.build();
            scanf("%s",buf);
    
            ac.query(buf,N);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    POJ3687拓扑排序+贪心
    POJ3687拓扑排序+贪心
    POJ3614奶牛晒阳光DINIC或者贪心
    POJ3614奶牛晒阳光DINIC或者贪心
    POJ3070矩阵快速幂简单题
    POJ3070矩阵快速幂简单题
    POJ3040给奶牛发工资
    POJ3040给奶牛发工资
    #Leetcode# 78. Subsets
    #Leetcode# 89. Gray Code
  • 原文地址:https://www.cnblogs.com/gongpixin/p/5139514.html
Copyright © 2020-2023  润新知