Trie图(模板)

Trie图(蒟蒻听说AC自动机能做的题Trie图都能做,而且AC自动机可能被卡,就没学过AC自动机),最近想捡一捡,好久之前做的了。

Trie图,就是一个在Trie树上建的图  大概描述一下

比如说有几个字符串:

abc

abcd

bcd

bacd

jdr

ac

先把它们存在Trie树中:

 

 就像KMP那样,做出这样的逻辑判断:

bacd比较到第三位bac结果没有d,但起码bac有了,所以以bac为前缀的或以bac后缀为前缀的串是不用再比较前缀了。

所以出现了fail指针,为失配情况重新定位方案。

类似于next数组。

无解(定位不到失配后新方案),就指向根表示无解。

显而易见,首字母失配是一定没有方案的。

其次,一个字母失配可以定位到父节点失配的自己值子节点。

一个优化:没有新子节点的节点直接指向fail指针自己值子节点。

建出来Trie图是这样的:

匹配时类似KMP:

模板代码(luogu P3808 【模板】AC自动机(简单版)):

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 struct trnt{
 6     int ch[26];
 7     int val;
 8     int fl;
 9 }tr[1000000];
10 std::queue<int>Q;
11 char tmp[1000003];
12 int siz;
13 int n;
14 void add(char *a)
15 {
16     int len=strlen(a+1);
17     int root=0;
18     for(int i=1;i<=len;i++)
19     {
20         int c=a[i]-'a';
21         if(!tr[root].ch[c])
22             tr[root].ch[c]=++siz;
23         root=tr[root].ch[c];
24     }
25     tr[root].val++;
26 }
27 void Build()
28 {
29     int root=0;
30     for(int i=0;i<26;i++)
31         if(tr[root].ch[i])
32             Q.push(tr[root].ch[i]);
33     while(!Q.empty())
34     {
35         root=Q.front();
36         Q.pop();
37         for(int i=0;i<26;i++)
38         {
39             if(tr[root].ch[i])
40             {
41                 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i];
42                 Q.push(tr[root].ch[i]);
43             }else
44                 tr[root].ch[i]=tr[tr[root].fl].ch[i];
45         }
46     }
47     return ;
48 }
49 int Cal(char *a)
50 {
51     int len=strlen(a+1);
52     int ans=0;
53     int root=0;
54     for(int i=1;i<=len;i++)
55     {
56         int c=a[i]-'a';
57         root=tr[root].ch[c];
58         for(int j=root;j&&(tr[j].val!=-1);j=tr[j].fl)
59         {
60             ans+=tr[j].val;
61             tr[j].val=-1;
62         }
63     }
64     return ans;
65 }
66 int main()
67 {
68     scanf("%d",&n);
69     for(int i=1;i<=n;i++)
70     {
71         scanf("%s",tmp+1);
72         add(tmp);
73     }
74     Build();
75     scanf("%s",tmp+1);
76     printf("%d\n",Cal(tmp));
77     return 0;
78 }

 

posted @ 2018-09-18 17:29  Unstoppable728  阅读(213)  评论(0编辑  收藏  举报