• HDU 2222 Keywords Search(AC自动机)


    题干:

      给定 n 个长度不超过 50 的由小写英文字母组成的单词准备查询,以及一篇长为m的文章,问:文中出现了多少个待查询的单词。多组数据

    题解:

      这是一道AC自动机的裸题(尽管你可以用hash+卡常A掉它。。。)。

      AC自动机其实也就两个核心部分:fail指针(或数组)、trie图

      1、fail指针(或数组)

      其实AC自动机类似于KMP算法,由KMP的单模式匹配优化为了多模式匹配。在KMP中,我们维护了一个Next[]数组(注意在NOIP中,next为保留字),他记录的就是当这一位失配后,最近的上一位匹配到的位置。而AC自动机也沿袭了这一思想,出现了fail数组(或fail指针),用来指向其它可与目标串部分匹配(至少从fail指向的那个节点开始,到根都是匹配的)的另一个串的一个节点。

      2、trie图

      trie图是在trie树基础上为了降低时间复杂度而出现一种技巧(可能你手中的模板就是trie图的。。。)。它的核心就是当x没有y这个儿子时,将x节点的不存在的儿子节点y,用fail[x]的对应儿子节点y'补齐,这样就在查询时节省了再跑回根节点在匹配的不必要的跑路时间。因为在连边(补齐儿子)的过程中,我们将树的性质破坏,变成了图,我们就将它叫做trie图。

     

    Code

      下面附上个人代码,不要随便颓代码。。。

     1 #include<cstring>
     2 #include<queue>
     3 #include<cstdio>
     4 #define   up(i,x,y,z) for(register int i=(x);i<=(y);i+=(z))
     5 #define down(i,x,y,z) for(register int i=(x);i>=(y);i-=(z))
     6 #define $ 511111
     7 using namespace std;
     8 char str[$*2];
     9 int m,n,tot,t;
    10 struct trie{
    11     int next[$][26],fail[$],end[$],count[$],root,length;
    12     inline int NewTrie(){
    13         up(i,0,25,1) next[length][i]=-1;
    14         end[length]=-1;
    15         count[length]=0;
    16         return length++;
    17     }
    18     inline void init(){    length=0; root=NewTrie();    }
    19     inline void insert(char *s,int id){
    20         int len=strlen(s);
    21         int x=root;
    22         up(i,0,len-1,1){
    23             if(next[x][s[i]-'a']==-1)  next[x][s[i]-'a']=NewTrie();
    24             x=next[x][s[i]-'a'];
    25         }
    26         end[x]=id;
    27         count[x]++;
    28     }
    29     inline void build(){
    30         queue<int> q;
    31         fail[root]=root;
    32         up(i,0,25,1){
    33             if(next[root][i]==-1)  next[root][i]=root;
    34             else fail[next[root][i]]=root,q.push(next[root][i]);
    35         }
    36         while(q.size()){
    37             int x=q.front(); q.pop();
    38             up(i,0,25,1){
    39                 if(next[x][i]==-1) next[x][i]=next[fail[x]][i];
    40                 else fail[next[x][i]]=next[fail[x]][i],q.push(next[x][i]);
    41             }
    42         }
    43     }
    44     
    45     inline int query(char *str,int n,int id){
    46         int len=strlen(str),x=root,ans=0,temp;
    47         up(i,0,len-1,1){
    48             x=next[x][str[i]-'a'];
    49             temp=x;
    50             while(temp!=root){
    51                 ans+=count[temp];
    52                 count[temp]=0;
    53                 temp=fail[temp];
    54             }
    55         }
    56         return ans;
    57     }
    58 }AC;
    59 signed main(){
    60     scanf("%d",&t);
    61     while(t--){
    62         scanf("%d",&n);
    63         AC.init();
    64         up(i,1,n,1) scanf("%s",str),AC.insert(str,i);
    65         AC.build();
    66         scanf("%s",str);
    67         printf("%d
    ",AC.query(str,n,1));
    68     }
    69 }
    数组版
     1 #include<cstdio>
     2 #include<queue>
     3 #include<cstring>
     4 #define $ 10000000 
     5 using namespace std;
     6 int m,n,t;
     7 char s[$],print[$];
     8 struct trie{    int sum;  trie *son[27],*fail;    };///4096
     9 inline trie *newnode(){
    10     trie *p=new trie;
    11     for(register int i=0;i<26;++i) p->son[i]=NULL;
    12     p->fail=NULL;    p->sum=0;
    13     return p;
    14 }
    15 inline void insert(trie *root){
    16     trie *p=root;
    17     for(register int i=1;i<=strlen(s+1);++i){
    18         int x=s[i]-'a';
    19         if(p->son[x]==NULL) p->son[x]=newnode();
    20         p=p->son[x];
    21     }
    22     p->sum++;
    23 }
    24 inline void build(trie *root){
    25     queue<trie*> q;
    26     for(register int i=0;i<26;++i){
    27         if(root->son[i]) root->son[i]->fail=root,q.push(root->son[i]);
    28         else root->son[i]=root;
    29     }
    30     while(q.size()){
    31         trie *p=q.front(); q.pop();
    32         for(register int i=0;i<26;++i){
    33             if(p->son[i]){
    34                 p->son[i]->fail=p->fail->son[i];
    35                 q.push(p->son[i]);
    36             }
    37             else p->son[i]=p->fail->son[i];
    38         }    
    39     }
    40 }
    41 inline void ac(trie *root){
    42     int ans=0,len=strlen(s+1);
    43     trie *p=root;
    44     for(register int i=1;i<=len;++i){
    45         int x=s[i]-'a';
    46         while(p->son[x]==NULL&&p!=root) p=p->son[x];
    47         p=p->son[x];
    48         trie *pp=p;
    49         while(pp->sum!=-1&&pp!=root){
    50             ans+=pp->sum;
    51             pp->sum=-1;
    52             pp=pp->fail;
    53         }
    54     }
    55     printf("%d
    ",ans);
    56 }
    57 inline void work(){
    58     trie *root=newnode();
    59     scanf("%d",&n);
    60     for(register int i=1;i<=n;++i) scanf("%s",s+1),insert(root);
    61     build(root);
    62     scanf("%s",s+1);  ac(root);
    63 }
    64 signed main(){
    65     scanf("%d",&t);
    66     while(t--) work();
    67 }
    指针版
    越努力 越幸运
  • 相关阅读:
    TPCDS tools生成数据:ERROR: Failed to open output file! File print.c Line: 490
    Caused by: com.typesafe.config.ConfigException$UnresolvedSubstitution: reference.conf @ jar:file:/home/FlinkIdeaDemo1.0.jar!/reference.conf: 875: Could not resolve substitution to a value:
    Searching from end of file using VIM
    How to kill server when seeing “EADDRINUSE: address already in use”
    IntelliJ IDEA – System.out.println shortcut
    intellij generate main method
    使用阿里云RDS for SQL Server性能洞察优化数据库负载初识性能洞察
    【转】包含前后端的插件开发指南
    [转]Understanding Kubernetes Architecture with Diagrams
    【转】路由表操作
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11108708.html
Copyright © 2020-2023  润新知