// 此博文为迁移而来,写于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. EF – 3.EF数据查询基础(下)数据关联

    5.5.1 <关于“数据关联”,你不一定清楚的事> 这讲视频比较全面地介绍了“一对一”.“一对多”和“多对多”三种数据关联类型在关系数据库和Entity Framework数据模型中的实现 ...

  2. Tensorflow 的Word2vec demo解析

    简单demo的代码路径在tensorflow\tensorflow\g3doc\tutorials\word2vec\word2vec_basic.py Sikp gram方式的model思路 htt ...

  3. Redis笔记(八)Redis的持久化

    Redis相比Memcached的很大一个优势是支持数据的持久化, 通常持久化的场景一个是做数据库使用,另一个是Redis在做缓存服务器时,防止缓存失效. Redis的持久化主要有快照Snapshot ...

  4. 设计模式学习之装饰者模式(Decorator,结构型模式)(16)

    参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...

  5. Delphi面向对象编程

    一.面向对象介绍 OOP是使用独立的对象(包含数据和代码)作为应用程序模块的范例.虽然OOP不能使得代码容易编写,但是它能够使得代码易于维护.将数据和代码结合在一起,能够使定位和修复错误的工作简单化, ...

  6. java-解决业务操可能数据冲突问题

    问题提出,由于业务会出现多人同时操作,或者业务人员反复的操作,因此在业务流程中,需要对业务操作数据进行保护,由于使用数据库锁可能会引起一些难以预料的问题,因此考虑使用内存锁,设计思想:在内存中使用一个 ...

  7. HDU1294 Rooted Trees Problem(整数划分 组合数学 DP)

    讲解见http://www.cnblogs.com/IMGavin/p/5621370.html, 4 可重组合 dfs枚举子树的节点个数,相乘再累加  1 #include<iostream& ...

  8. Linux SSH远程文件/目录传输命令scp

    转载地址:http://www.vpser.net/manage/scp.html 相信各位VPSer在使用VPS时会经常在不同VPS间互相备份数据或者转移数据,大部分情况下VPS上都已经安装了Ngi ...

  9. 第一次尝试用 Live Writer 写博客

    之前在官网上下载了最新版的Windows Live Writer,可是安装不了,就在其他网站下了一个试试,可以安装,不过却是2009年的版本,很不喜欢,我希望能体验最新版的,回头还得重新下个最新版的安 ...

  10. 【Debug 报异常】Debug打断点报错

    用DEBUG启动项目,项目中打断点的,然后会报异常 解决方法: 第一步: 项目-->Java编译器-->Classfile Generation 复选框 全部勾选 第二步: 替换当前文件运 ...