// 此博文为迁移而来,写于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. Jquery.Datatables td宽度太长的情况下,自动换行

    在 td 里面 加上 style="word-wrap:break-word;" 自动换行就好了,如果不想换行,可以将超出内容设为隐藏, overflow:hidden; whit ...

  2. DedeCMS Error: (PHP 5.3 and above) Please set request_order

    部分使用PHP 5.3的主机可能会有下面的提示: (PHP 5.3 and above) Please set 'request_order' ini value to include C,G and ...

  3. Android 下拉刷新

    以前旧版用的是开源的PullToRefresh第三方库,该库现在已经不再维护了: chrisbanes/Android-PullToRefreshhttps://github.com/chrisban ...

  4. 讲解JS的promise,这篇是专业认真的!

    http://www.zhangxinxu.com/wordpress/2014/02/es6-javascript-promise-%E6%84%9F%E6%80%A7%E8%AE%A4%E7%9F ...

  5. GoLang搞一个基本的HTTP服务

    慢慢和python的对应一下看看. package main import ( "fmt" "net/http" "strings" &qu ...

  6. thinkphp 两表、三表联合查询

    //两表联合查询 $Model = M('T1');$Model->join('left join t2 on t1.cid = t2.id')->select();// $list = ...

  7. C[泊车管理系统]

    // //  main.c //  泊车管理系统 // //  Created by 丁小未 on 13-7-14. //  Copyright (c) 2013年 dingxiaowei. All ...

  8. Android开发如何去除标题栏title(转)

    去除标题栏title其实非常简单,他有两种方法,一种是在代码中添加,另一种是在AndroidManifest.xml中添加: 1.在代码中实现:在此方法setContentView(R.layout. ...

  9. Xcode 缓存 帮助文档 隐藏文件夹显示方法

    删除Xcode的缓存路径是:/Users/用户名/Library/Developer/Xcode/DerivedData(默认情况下, 这是一个隐藏文件夹) 显示隐藏文件夹 指令如下:显示隐藏文件: ...

  10. UVA136 求第1500个丑数

    枚举大范围数据..暴力检查题目条件 #include <iostream> #include <cstdio> #include <vector> #include ...