zoukankan      html  css  js  c++  java
  • 【模板】AC自动机(加强版)

    题目描述

    个由小写字母组成的模式串以及一个文本串。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串中出现的次数最多。

    输入输出格式

    输入格式:

    输入含多组数据。

    每组数据的第一行为一个正整数,表示共有个模式串,

    接下去行,每行一个长度小于等于的模式串。下一行是一个长度小于等于的文本串

    输入结束标志为

    输出格式:

    对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

    输入输出样例

    输入样例#1:
    2
    aba
    bab
    ababababac
    6
    beta
    alpha
    haha
    delta
    dede
    tata
    dedeltalphahahahototatalpha
    0
    输出样例#1:
    4
    aba
    2
    alpha
    haha
    解法1:。。。。。。。。8813ms
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    struct Tree{int fail,vis[26],end;}AC[100000];//Trie tree
    //vis:son_points' position
    //end:mark the word_number end with this point
    int cnt=0;//Trie's pointer
    struct Result{int num,pos;}Ans[100000];//mark every word's appear_times
    bool operator <(Result a,Result b){if(a.num!=b.num)return a.num>b.num;else return a.pos<b.pos;}//operate the < operation 
    //if it's appear_times higher.just return it,or just return the one have lower pos
    string s[100000];
    inline void Clean(int x){memset(AC[x].vis,0,sizeof(AC[x].vis));AC[x].fail=0;AC[x].end=0;}
    //initialization
    inline void Build(string s,int Num){
            int l=s.length(),now=0;//l:mark the length,now:mark the now_position
            for(int i=0;i<l;++i)//make Trie_tree
            {// if the Trie tree has not this point
                    if(AC[now].vis[s[i]-'a']==0)AC[now].vis[s[i]-'a']=++cnt,Clean(cnt);
                       //if has not been visited ,just go on
                       //add it to now's son_points and then initialization it 
                    now=AC[now].vis[s[i]-'a'];//just run to next level
            }AC[now].end=Num;//mark the end 
    }
    void Get_fail()//make fail
    {queue<int> Q;//set a queue
            for(int i=0;i<26;++i)if(AC[0].vis[i]!=0)//if it has not been visited
                        AC[AC[0].vis[i]].fail=0,Q.push(AC[0].vis[i]);
                   //just point it to the root_point and then push it to the queue 
            while(!Q.empty())//BFS to ask for fail
            {int u=Q.front();Q.pop();//use u to mark the queue_head,and then push it out 
                  for(int i=0;i<26;++i)
                       if(AC[u].vis[i]!=0)//it it has been visited,just it is real
                          AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i],Q.push(AC[u].vis[i]);
                          //make it's son_point's fail against now_fail_son(renew)
                          //and then push then son_point to the queue
                          else AC[u].vis[i]=AC[AC[u].fail].vis[i];
                          //or ,this point has not been visited
                          //just it is not real
                          //just use it's fail(spare tire)
            }
    }
    int AC_Query(string s){int l=s.length(),now=0,ans=0;
            for(int i=0;i<l;++i){
                    now=AC[now].vis[s[i]-'a'];
                    for(int t=now;t;t=AC[t].fail)Ans[AC[t].end].num++;
            }return ans;
    }
    int main(){int n;
         while(1){scanf("%d",&n);if(n==0)break;cnt=0;Clean(0);
             for(int i=1;i<=n;++i)cin>>s[i],Ans[i].num=0,Ans[i].pos=i,Build(s[i],i);
             //read every given_part(key),initialization it
             AC[0].fail=0;Get_fail();
             //initialization root's fail and want fail
             cin>>s[0];AC_Query(s[0]);
             //read the given_long_word and ask for the ans
             sort(&Ans[1],&Ans[n+1]);printf("%d
    ",Ans[1].num);
             //sort the ans and printf the biggest solution
             cout<<s[Ans[1].pos]<<endl;//give the appear_most_often_word
             for(int i=2;i<=n;++i)if(Ans[i].num==Ans[i-1].num)cout<<s[Ans[i].pos]<<endl;else break;
             //then if have more than one solution, just printf them
             //after sort ,the appear_most_often_word must be in the front
             //and the Ans[1] has printf just start from 2
             //if it is not the best solution,it means there is no best solution any more,just break 
         }return 0;
    }//this program's speed is very slow,can only accept just in time 
    //maybe we should search for a better solution

    虽然实现的很自然,但是这效率。。。。。。光荣地拿到了luogu rank 倒数第一

    能有更好的解法吗?

    自然是有的。

    解法2:1688ms最慢点464ms

    无注解,清新模板版

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #define maxn 15000
    #define maxc 1000005
    #define For(a,b,c) for(a=b;a<=(int)(c);++a)
    using namespace std;
    int n;
    char T[maxc],P[151][71];
    inline int idx(char c){return c-'a';}
    struct Trie{int sz,ch[maxn][26],val[maxn];
        inline void init(){sz=0;memset(ch,0,sizeof(ch));memset(val,0,sizeof(val));}
        inline void insert(char *s,int v){
            int i,u=0,l=strlen(s);
            For(i,0,l-1){int c=idx(s[i]);
                if(!ch[u][c])ch[u][c]=++sz;u=ch[u][c];
            }val[u]=v;}
    }tr;
    struct AC_machine{int fail[maxn],last[maxn],cnt[maxn];
        inline void init(){memset(fail,0,sizeof(fail));memset(last,0,sizeof(last));memset(cnt,0,sizeof(cnt));}
        inline void getfail(){int c,u,k,r;queue<int>q;fail[0]=0;
            For(c,0,25)if(tr.ch[0][c])q.push(tr.ch[0][c]);
            while(!q.empty()){r=q.front(),q.pop();
                For(c,0,25){u=tr.ch[r][c];
                    if(!u){tr.ch[r][c]=tr.ch[fail[r]][c];continue;}q.push(u);
                    k=fail[r];while(k&&!tr.ch[k][c])k=fail[k];
                    fail[u]=tr.ch[k][c];
                    last[u]=tr.val[fail[u]]?fail[u]:last[fail[u]];
                }}}
        inline void calc(int x){while(x)++cnt[tr.val[x]],x=last[x];}
        inline void find(char *s){int i,j,l=strlen(s);
            For(i,0,l-1){j=tr.ch[j][idx(s[i])];
                if(tr.val[j])calc(j); else if(last[j]) calc(last[j]);}}
    }ac;
    int main(){int i;
        while(scanf("%d",&n),n){tr.init();ac.init();
            For(i,1,n)scanf("%s",P[i]),tr.insert(P[i],i);
            scanf("%s",T);ac.getfail();ac.find(T);
            int best=-1;
            For(i,1,n) if(ac.cnt[i]>best) best=ac.cnt[i];
            printf("%d
    ",best);
            For(i,1,n)if(ac.cnt[i]==best)printf("%s
    ",P[i]);
        }return 0;}
  • 相关阅读:
    J2那几个E和Web基础
    PHP开发人员对JAVA的WEB开发入门(初版-基础知识)
    一个处理大数据的后台服务(已废弃)
    一个请求过来都经过了什么
    请一定记得升级java虚拟机
    面向对象之 结构体和类的区别
    Swift 结构体的使用
    iOS 波浪效果的实现
    iOS 常用三方(持续更新)
    Xshell 链接 Could not connect to '192.168.80.129' (port 22): Connection failed
  • 原文地址:https://www.cnblogs.com/muzu/p/7145910.html
Copyright © 2011-2022 走看看