// 此博文为迁移而来,写于2015年5月27日,不代表本人现在的观点与看法。原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w1s8.html

1、前言
       怪我咯,因为Trie树和AC自动机的密切相关,我想一起讲完哈哈。。。看过前面博文的同学应该都知道了,AC自动机其实就是相当于在Trie树上跑KMP。
       
2、Trie树
       Trie树,就是字母树。Trie树是多叉树,每个节点为一个字母。其根节点为象征节点(就是说没有含义,但是存在这个节点),从根节点开始建立,每个节点至多为26个子节点(不要我说为什么吧),这样,我们就可以用这种方便快捷的方式存储字符串。其应用也不言而喻,用于保存,统计,排序,查找大量字符串。因为很简单,我们不讲太多,根据图像,自己造几个字符串,慢慢理解,看看代码,一下就懂了。

       如图所示,该字符串保存了say,she,shr,her四个字符串。有个小小的问题:在建树的时候,我们注意到最坏情况可能为二十六叉树,空间复杂度可想而知。所以,如果用指针可能更省空间。
 
3、构造fail指针(KMP)
       在网上看到有许多AC自动机的算法分析,但是发现好像都很相似(莫非都是Ctrl+C/V)。构造fail指针,使当前字符失配时跳转到具有最长公共前后缀的字符继续匹配。如同 KMP算法一样, AC自动机在匹配时如果当前字符匹配失败,那么利用fail指针进行跳转。由此可知如果跳转,跳转后的串的前缀,必为跳转前的模式串的后缀。并且跳转的新位置的深度(匹配字符个数)一定小于跳之前的节点。
       我们在构建好Trie树之后,可以利用BFS进行 fail指针求解。我们最开始先将root节点入队,因为第一个字符不匹配需要重新匹配,所以第一个字符都指向root。这样,我们得到下图:

3、例题
Keywords Search [ HDU 2222 ]
       In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.
Wiskey also wants to bring this feature to his image retrieval system.
       Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched.
      To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match. (well, it's about time to exercise your English !)
 
输入格式
       First line will contain one integer means how many cases will follow by.
       Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000)
       Each keyword will only contains characters 'a'-'z', and the length will be not longer than 50.
       The last line is the description, and the length will be not longer than 1000000.
 
输出格式
       Print how many keywords are contained in the description.
 
输入样例
1
5
she
he
say
shr
her
yasherhs
 
输出样例
3
 
Code:
-----------------------------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#define MAXN 105
#define MAXM 1000005
 
struct Node
{
        int next[30],x,fail,num,count;
};
Node tree[MAXM];
 
int n,tot,nowLen,root,t,q[MAXM];
char article[MAXM],word[MAXN];
 
void insert()
{
        int temp,now=root,len=strlen(word); 
        for (int i=0;i<=len-1;i++)
        {
                temp=word[i]-'a';
                if (tree[now].next[temp]==0) { tot++; tree[now].next[temp]=tot; }
                now=tree[now].next[temp];
        }  
        tree[now].count++;
}
 
void getFail()
{
        int head=1,tail=2;
        q[1]=root;
        while (head!=tail)
        {
                for (int i=0;i<=25;i++)
                {
                        int next=tree[q[head]].next[i];
                        if (next!=0)
                        {
                                if (q[head]==root) tree[next].fail=root;
                                else
                                {
                                        int temp=tree[q[head]].fail;
                                        while (temp!=0)
                                        {
                                                if (tree[temp].next[i]!=0)
                                                {
                                                        tree[next].fail=tree[temp].next[i];
                                                        break;
                                                }
                                                temp=tree[temp].fail;
                                        }
                                        if (temp==0) tree[next].fail=root;
                                }
                                q[tail++]=next;
                        }
                } 
                head++;
        }
}
 
int find()
{
        int len=strlen(article),ans=0,n1=root;
        for (int i=0;i<=len-1;i++)
        {
                int now=article[i]-'a';
                while (tree[n1].next[now]==0 && n1!=root) n1=tree[n1].fail;
                n1=tree[n1].next[now];
                if (n1==0) n1=root;
                int n2=n1;
                while (n2!=root && tree[n2].count!=-1)
                {
                        ans+=tree[n2].count;
                        tree[n2].count=-1;
                        n2=tree[n2].fail;
                }
        }
        return ans;
}
 
int main()
{
        freopen("AC.in","r",stdin);
        freopen("AC.out","w",stdout);
        scanf("%d",&t); 
        for (int j=1;j<=t;j++)
        {
                scanf("%d",&n);
                root=tot+1; tot++;
                for (int i=1;i<=n;i++) 
                {
                        scanf("%s",word); nowLen=strlen(word)-1;
                        insert();
                }
                getFail(); for (int i=root+1;i<=tot;i++) if (tree[i].fail==0) tree[i].fail=root;
                scanf("%s",article);
                printf("%d\n",find());
        }
        return 0;
-----------------------------------------------------------------------------------------------------

[知识点]Trie树和AC自动机的更多相关文章

  1. 算法笔记--字典树(trie 树)&& ac自动机 && 可持久化trie

    字典树 简介:字典树,又称单词查找树,Trie树,是一种树形结构,是哈希树的变种. 优点:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较. 性质:根节点不包含字符,除根节点外每一个 ...

  2. [HNOI2004]L语言 trie树? Ac自动机? hash!!

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  3. Trie树&kmp&AC自动机&后缀数组&Manacher

    Trie 计数+Trie,读清题意很重要 https://vjudge.net/problem/UVALive-5913 kmp AC自动机 模板:https://vjudge.net/problem ...

  4. 从Trie谈到AC自动机

    ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字 ...

  5. HDU 5384 字典树、AC自动机

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5384 用字典树.AC自动机两种做法都可以做 #include<stdio.h> #includ ...

  6. 中文分词系列(二) 基于双数组Tire树的AC自动机

    秉着能偷懒就偷懒的精神,关于AC自动机本来不想看的,但是HanLp的源码中用户自定义词典的识别是用的AC自动机实现的.唉-没办法,还是看看吧 AC自动机理论 Aho Corasick自动机,简称AC自 ...

  7. 【AC自动机】【字符串】【字典树】AC自动机 学习笔记

    blog:www.wjyyy.top     AC自动机是一种毒瘤的方便的多模式串匹配算法.基于字典树,用到了类似KMP的思维.     AC自动机与KMP不同的是,AC自动机可以同时匹配多个模式串, ...

  8. Trie图(AC自动机)总结

    AC自动机构建完成后,某个节点沿着Fail链向上能从长到短走到自己的所有后缀.一般的,遍历主串进行匹配,就是在Trie图上定向移动的过程. 构造(一遍 BFS) void build_AC() { ; ...

  9. 【uva1502/hdu4117-GRE Words】DP+线段树优化+AC自动机

    这题我的代码在hdu上AC,在uva上WA. 题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串.问d值的和最大是多少. (1≤n≤2×10^4 ,串的总长度< ...

随机推荐

  1. 与你相遇好幸运,mbview的mbtiles文件分析

    mbview是一个查看.mbtiles文件的本地程序. https://github.com/mapbox/mbview .mbtiles文件就是一个Sqlite文件,用Navicat Premium ...

  2. Oracle数据库备份与还原操作具体步骤

    Oracle数据库导出操作 导入导出都要进行目录创建与授权. 在pl/sql里面编写也可以 select * from dba_directories(这个是查看创建的目录) drop directo ...

  3. HTTP中302与301的区别以及在ASP.NET中如何实现

    一.官方说法301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于: 301 redirect: 301 代表永久性转移(Permanently Moved).302 re ...

  4. 一个简单的Promise 实现

    用了这么长时间的promise,也看了很多关于promise 的文章博客,对promise 算是些了解.但是要更深的理解promise,最好的办法还是自己实现一个. 我大概清楚promise 是对异步 ...

  5. <转>ORA-06413 连接未打开错误

    ORA-06413 Connection not open.Cause: Unable to establish connection.Action: Use diagnostic procedure ...

  6. html5 svg

    html5 svg <html > <body> <p>canvas 用js 绘画,是整幅画布,适合游戏 svg可放大,支持dom 操作,js事件 线性渐变.高斯模 ...

  7. 来访统计的JS代码

    <script language="JavaScript"> var caution = false function setCookie(name, value, e ...

  8. Matlab tips and tricks

    matlab tips and tricks and ... page overview: I created this page as a vectorization helper but it g ...

  9. Sublime Text 3 安装Go语言相关插件gosublime

    1.打开Sublime Text,使用快捷键 ctrl+` (左上角Tab键上方,Esc键下方)或者使用菜单 View > Show Console menu,此时将出现Sublime Text ...

  10. ios编码转换 国标 UTF-8

    我们知道,使用NSURLConnection的代理方法下载网页,存到一个NSData中, NSMutableData *pageData; [pageData appendData:data]; 如果 ...