[知识点]Trie树和AC自动机

// 此博文为迁移而来,写于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;

}

-----------------------------------------------------------------------------------------------------

时间: 2024-11-09 02:22:38

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

从Trie谈到AC自动机

ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字母,因此得名`字母树`. 出一张图让大家感受下. (image powered by SaiBu NaoCu) 上面那是一棵插入了 ape,app,applicant,application,bake,ban,banana 等词的Trie.红色结点表示接受态. 显然,查找时只需顺着链照下来,插入只需

HDU 5384 字典树、AC自动机

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5384 用字典树.AC自动机两种做法都可以做 1 #include<stdio.h> 2 #include<string.h> 3 #include<string> 4 #include<iostream> 5 using namespace std; 6 struct node{ 7 int cnt; 8 node *next[26]; 9 node(){ 10 c

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

秉着能偷懒就偷懒的精神,关于AC自动机本来不想看的,但是HanLp的源码中用户自定义词典的识别是用的AC自动机实现的.唉-没办法,还是看看吧 AC自动机理论 Aho Corasick自动机,简称AC自动机,要学会AC自动机,我们必须知道什么是Trie,也就是字典树.Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高.之

hihoCoder #1036 : Trie图 (AC自动机)

#1036 : Trie图 时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:"枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功."这样非常朴素的想法,但是这样的算法时间复杂度是相当

LA_3942 LA_4670 从字典树到AC自动机

首先看第一题,一道DP+字典树的题目,具体中文题意和题解见训练指南209页. 初看这题模型还很难想,看过蓝书提示之后发现,这实际上是一个标准DP题目:通过数组来储存后缀节点的出现次数.也就是用一颗字典树从后往前搜一发.最开始觉得这种搞法怕不是要炸时间,当时算成了O(N*N)毕竟1e5的数据不搞直接上N*N的大暴力...后来发现,字典树根本跑不完N因为题目限制字典树最多右100层左右. 实际上这道题旧思想和模型来说很好(因为直观地想半天还真想不出来..)但是实际实现起来很简单--撸一发字典树就好了

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

这题我的代码在hdu上AC,在uva上WA. 题意:按顺序输入n个串以及它的权值di,要求在其中选取一些串,前一个必须是后一个的子串.问d值的和最大是多少. (1≤n≤2×10^4 ,串的总长度<=3*10^5) 题解: 这题一开始我的方向就错了,想了很久d[x][y]表示在AC自动机上的节点x.下一个串要大于y的dp.然而这样做数组要10^4*10^5=10^9级别,开都开不了,妥妥超时. 后来看了一眼题解...觉得自己智商真是感人... 用f[i]表示以第i个串为结尾的时候最大的d值,这样做

hihocoder 1036 Trie图(AC自动机)

传送门 Description 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本厚厚的河蟹词典,而他们要做的是判断这篇文章中是否存在那些属于河蟹词典中的词语. 当时,小Hi和小Ho的水平还是十分有限,他们只能够想到:“枚举每一个单词,然后枚举文章中可能的起始位置,然后进行匹配,看能否成功.”这样非常朴素的想法,但是这样的算法时间复杂度是相当高的,如果说词典的词语数量为N,每个词语长度为L,文章的长度为M,那么需要进行的计算次数是在N

[HIHO1036] Trie图(AC自动机)

题目链接:http://hihocoder.com/problemset/problem/1036 不知道为什么匹配到某点存在next[idx]的时候,只需要检查这一个sign就行,如果检查此点的fail的sign就会TLE. 大概数据比较弱能让我水过吧. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef struct Node { 5 Node* fail; 6 Node* next[26]; 7 bool sign;

多模字符串匹配算法之AC自动机—原理与实现

简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上是KMP算法的树形扩展.这篇文章主要介绍AC自动机的工作原理,并在此基础上用Java代码实现一个简易的AC自动机. 欢迎探讨,如有错误敬请指正 如需转载,请注明出处 http://www.cnblogs.com/nullzx/ 1. 应用场景-多模字符串匹配 我们现在考虑这样一个问题,在一个文本串t