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

    AC自动机是一种多模式匹配的算法。大概过程如下:

    • 首先所有模式串构造一棵Trie树,Trie树上的每个非根结点都代表一个从根出发到该点路径的字符串。
    • 然后每个结点都计算出其fail指针的值,这个fail指针就指向这个结点所表示字符串的最长存在的后缀所对应的结点,如果不存在就指向根:计算每个结点的fail用BFS,比如当前结点u出队要拓展并计算其孩子结点的fail,v是其第k个孩子,fail[v]的值就是某个fail[fail[fail...[u]]]存在第k孩子结点其第k个孩子结点,如果不存在fail[v]就等于root。
    • 最后主串就往Trie树上跑,在某个Trie树结点失配了就跳转到这个结点fail指针所指的结点继续跑——不过如果匹配了某个模式串这时可能某个模式串的后缀串被忽略了,所以需要用到temp指针,去检查是否有遗漏后缀没匹配。

    而这题大概就是给几个模式串,一个主串,问有几个模式串被主串匹配。

    AC自动机的模板题。有个可以优化的地方就是某个模式串被匹配了,下一次经过这儿就可以跳过了temp指针的过程了。

    代码参考自kuangbin巨的博客,太简洁了(300+ms):

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue> 
     4 using namespace std;
     5 int tn,ch[510000][26],cnt[510000],fail[510000];
     6 void insert(char *s){
     7     int x=0;
     8     for(int i=0; s[i]; ++i){
     9         int y=s[i]-'a';
    10         if(ch[x][y]==0) ch[x][y]=++tn;
    11         x=ch[x][y];
    12     }
    13     ++cnt[x];
    14 }
    15 void init(){
    16     memset(fail,0,sizeof(fail));
    17     queue<int> que;
    18     for(int i=0; i<26; ++i){
    19         if(ch[0][i]) que.push(ch[0][i]);
    20     }
    21     while(!que.empty()){
    22         int x=que.front(); que.pop();
    23         for(int i=0;i<26;++i){
    24             if(ch[x][i]) que.push(ch[x][i]),fail[ch[x][i]]=ch[fail[x]][i];
    25             else ch[x][i]=ch[fail[x]][i];
    26         }
    27     }
    28 }
    29 int query(char *s){
    30     int x=0,res=0;
    31     for(int i=0; s[i]; ++i){
    32         int tmp=x=ch[x][s[i]-'a'];
    33         while(tmp){
    34             if(cnt[tmp]>=0){
    35                 res+=cnt[tmp];
    36                 cnt[tmp]=-1;
    37             }else break;
    38             tmp=fail[tmp];
    39         }
    40     }
    41     return res;
    42 }
    43 char S[1100000],T[55];
    44 int main(){
    45     int t,n;
    46     scanf("%d",&t);
    47     while(t--){
    48         tn=0;
    49         memset(ch,0,sizeof(ch));
    50         memset(cnt,0,sizeof(cnt));
    51         scanf("%d",&n);
    52         while(n--){
    53             scanf("%s",T);
    54             insert(T);
    55         }
    56         init();
    57         scanf("%s",S);
    58         printf("%d
    ",query(S));
    59     }
    60     return 0;
    61 }

    另外之前学的指针版本的,指针版本跑得更快(200+ms):

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 using namespace std;
     5 typedef struct Node *pNode;
     6 struct Node{
     7     int cnt;
     8     pNode fail,nxt[26];
     9     Node(){
    10         cnt=0; fail=NULL;
    11         for(int i=0;i<26;++i) nxt[i]=NULL;
    12     }
    13 };
    14 pNode root;
    15 char S[1000100];
    16 void insert(char *s){
    17     pNode p=root;
    18     for(int i=0;s[i];++i){
    19         int index=s[i]-'a';
    20         if(p->nxt[index]==NULL){
    21             p->nxt[index]=new Node;
    22         }
    23         p=p->nxt[index];
    24     }
    25     ++p->cnt;
    26 }
    27 void init(){
    28     queue<pNode> que;
    29     que.push(root);
    30     while(que.size()){
    31         pNode y=que.front(); que.pop();
    32         for(int i=0;i<26;++i){
    33             if(y->nxt[i]==NULL) continue;
    34             if(y==root){
    35                 y->nxt[i]->fail=root;
    36                 que.push(y->nxt[i]);
    37                 continue;
    38             }
    39             pNode x=y->fail;
    40             while(x&&x->nxt[i]==NULL) x=x->fail;
    41             if(x==NULL) y->nxt[i]->fail=root;
    42             else y->nxt[i]->fail=x->nxt[i];
    43             que.push(y->nxt[i]);
    44         }
    45     }
    46 }
    47 int query(){
    48     int res=0;
    49     pNode x=root;
    50     for(int i=0;S[i];++i){
    51         int index=S[i]-'a';
    52         while(x->nxt[index]==NULL&&x!=root) x=x->fail;
    53         x=x->nxt[index];
    54         if(x==NULL) x=root;
    55         pNode y=x;
    56         while(y!=root){
    57             if(y->cnt>=0){
    58                 res+=y->cnt;
    59                 y->cnt=-1;
    60             }else break;
    61             y=y->fail;
    62         }
    63     }
    64     return res;
    65 }
    66 int main(){
    67     int t,n;
    68     char s[55];
    69     scanf("%d",&t);
    70     while(t--){
    71         root=new Node;
    72         scanf("%d",&n);
    73         for(int i=0;i<n;++i){
    74             scanf("%s",s);
    75             insert(s);
    76         }
    77         scanf("%s",S);
    78         init();
    79         printf("%d
    ",query());
    80     }
    81     return 0;
    82 } 
  • 相关阅读:
    Chat Application using Web services in C#(转载)
    Asynchronous Method Invocation(转载)
    Passing Data between Windows Forms(转载)
    Fill in PDF Form Fields using the Open Source iTextSharp Dynamic Link Library(转载)
    The ShutDown Alarm(转载)
    使用blowery.Web.HttpCompress.dll对aspx压缩
    C# Voice and Tone Alert Generator(转载)
    Compress Folders with C# and the SharpZipLib(转载)
    Ubuntu 12.10 修改窗口按键布局(buttom_layout)到右边
    同步CM9源代码
  • 原文地址:https://www.cnblogs.com/WABoss/p/5164457.html
Copyright © 2011-2022 走看看