突然发现自己还不会AC自动姬,就去学了一下下。。。

自动姬de用途:

给你n个模式串,1个文本串,求出有多少模式串在文本串中出现过。(详见洛谷P3808)

大体思路:

我先前貌似介绍过一种叫做KMP的神奇东西,还有叫做trie树的逆天玩意儿,嗯,今天要讲的AC自动姬就是两者相结合,诞生的产品啦。

(图片来自百度)

嗯,看到上面的图片,让我们手动过滤掉那些虚线,剩下的就是一颗加入了he,she,his,hers,四个字符串的trie树了。

基础trie树的构建(代码):

void insert(char *s){int now=0;for (int i=0;s[i];i++){if (!trie[now][s[i]-'a']) trie[now][s[i]-'a']=++tot;now=trie[now][s[i]-'a'];}end[now]++;
}

Fail指针:

那么那些虚线又是什么鬼呢?

其实,它就是自动姬的精髓所在,我们称它为Fail指针(也叫失配指针)。

我觉得失配指针这个名字取的特别形象,因为fail指针的作用就是在文本串与当前串失去匹配后的退路

什么意思呢?

比如说:文本串在she的h处与模式串失去了匹配(也就是说文本串的下一个字符不是‘e’),也就是说,我们现在被字符串“she”给炒鱿鱼了,那么我们应该怎么做呢,无家可归了吗?

不要慌——既然“she”不要你了,但是我们“his”还是要你的,毕竟你有字符‘h’在,和我们‘his’的前一个字符是相符合的,你可以来我们这里试试看,假如说合适的话,就留下好了。

这样就很容易理解了吧!

我们fail指针的作用就是为了找到这样一条“后路”

那么假如说我们真的沦落到了没人要的地步,也不用担心,我们“家里蹲”(家,是最温暖的港湾)还是会收留你的,嗯,没错,真的没人要的话,只要把fail指针指向根节点就行了。

我们可以采用BFS的方式来求出这个fail指针。

求出当前节点的fail指针的条件是:我们已经求出了之前所有节点的fail指针。    这里的“之前”指的就是所有深度小于当前节点的点,所以才要用BFS来实现嘛。

为什么会有这个前置条件呢,换句话说,为什么我们知道了这些就能求出当前节点的fail指针呢?

这还得从fail指针的定义出发——失配后的退路,也就是说,我们要找到当前串的部分后缀与其它模式串的前缀完全相同的节点,fail指针便是指向这个节点的。

所以,当前的fail指针肯定会指向深度小于等于当前节点的节点。

具体我们可以怎么做呢,其实很简单。

因为要和当前串的部分后缀完全相同,说明肯定要和前一个字符为止的部分后缀完全相同嘛,所以我们就先要找到fail[s[i-1]]指向的节点,假如说它有s[i]这个儿子的话,那么fail指针就指向它的这个儿子了,如果没有的话,我们就要顺着这个节点的fail指针接着向上找,一直到找到或者到达根节点为止。

我们会很清楚的感觉到:在顺着节点的fail指针不断往上找的过程中,与当前串的后缀完全相同的前缀的部分的长度是在不断减小的。(貌似很拗口,但是如果你有这种感觉的话,就说明你对AC自动姬的学习已经有点感觉了)

Fail指针的构建(代码):

void build(){queue <int> q;for (int i=0;i<26;i++) if (trie[0][i]) q.push(trie[0][i]);while (!q.empty()){int now=q.front(); q.pop();for (int i=0;i<26;i++)if (trie[now][i])fail[trie[now][i]]=trie[fail[now]][i],q.push(trie[now][i]);else trie[now][i]=trie[fail[now]][i];//注意了,这行代码非常精髓,把原本我们可能要跳多次的环节,直接省略到了一次,因为这句话在执行一个“路径压缩”的操作,把一些没用的(跳了之后发现没有想要儿子的)跳跃全部都省去了}
}

与文本串的匹配:

有了构建Fail指针时的路径压缩之后,查询操作就显的简单多了,因为路径压缩后,我们把一些前缀与当前串的部分后缀相同的节点都连接到了这个节点下方,比如“she”和“her”,以为she的后缀he是与her的前缀he完全相同的,所以路径压缩操作会给当前节点(当前节点是指通过she到达的节点,也就是5号点)新加入一条边‘r’(图中红色的那条),连到沿着her走到达的节点(也就是8号点)。所以我们就可以实现在自动姬上反复横跳啦。

(哔——————————————————————————————————

这样的话,我们就可以无脑在自动姬上跳来跳去,一直顺着文本串在自动姬上走就行了,然后再走的过程中,我们把fail指针能知道的模式串一路遍历过去,统计他们的出现就好。

查询操作(代码):

int query(char *s){int now=0,res=0;for (int i=0;s[i];i++){now=trie[now][s[i]-'a'];for (int j=now;j&&~end[j];j=fail[j]) res+=end[j],end[j]=-1;}return res;
}

完整代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000005;
char s[maxn];
int trie[maxn][30],fail[maxn],end[maxn],n,tot;
void insert(char *s){int now=0;for (int i=0;s[i];i++){if (!trie[now][s[i]-'a']) trie[now][s[i]-'a']=++tot;now=trie[now][s[i]-'a'];}end[now]++;
}
void build(){queue <int> q;for (int i=0;i<26;i++) if (trie[0][i]) q.push(trie[0][i]);while (!q.empty()){int now=q.front(); q.pop();for (int i=0;i<26;i++)if (trie[now][i])fail[trie[now][i]]=trie[fail[now]][i],q.push(trie[now][i]);else trie[now][i]=trie[fail[now]][i];}
}
int query(char *s){int now=0,res=0;for (int i=0;s[i];i++){now=trie[now][s[i]-'a'];for (int j=now;j&&~end[j];j=fail[j]) res+=end[j],end[j]=-1;}return res;
}
int main(){scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%s",s),insert(s);build();scanf("%s",s);printf("%d\n",query(s));return 0;
} 

转载于:https://www.cnblogs.com/WR-Eternity/p/9970216.html

关于【AC自动姬】的学习相关推荐

  1. hdu 2243 考研路茫茫——单词情结(AC自动+矩阵)

    考研路茫茫--单词情结 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  2. 新论文推荐:Auto-Keras:自动搜索深度学习模型的网络架构和超参数

    Auto-Keras 是一个开源的自动机器学习库,由美国德州农工大学(Texas A&M University)助理教授胡侠和他的两名博士生:金海峰.Qingquan Song提出.Auto- ...

  3. poj--1625Censored!+AC自动机上的dp+大数

    题目链接:点击进入 其实看起来是完全可以用矩阵做的,但是因为用到了大数的,导致内存开不下,所以用dp写了.其实dp的过程依旧就是在我们用禁止出现单词构建的trie上走m步的过程.我们定义dp[i][j ...

  4. 自动驾驶深度学习常用中英文对照表

    自动驾驶深度学习常用中英文对照表 A B C D E F G H I J K L M N O P Q R S T U V W Z A 英文 中文 词性 activation 激活值 n,名词 acti ...

  5. 人工智能在自动驾驶深度学习中的应用

    人工智能在自动驾驶深度学习中的应用 驾驶员认知靠大脑,无人驾驶汽车的"大脑"则是计算机.无人车里的计算机与我们常用的台式机.笔记本略有不同,因为车辆在行驶的时候会遇到颠簸.震动.粉 ...

  6. [BZOJ4044]-Virus synthesis-回文自动姬+DP

    说在前面 me真的-觉得自己很棒棒 一个小时不到敲完了,提交然后WA,以为自己板子写错了,然而对照着之前的代码发现并没有错 然后me在花式TLE,RE,WA之后,确定是有一个地方搞成了NULL,然而逻 ...

  7. 陈天奇团队新研究:自动优化深度学习工作负载

    深度学习在我们的日常生活中已经无处不在.深度学习模型现在可以识别图像,理解自然语言,玩游戏,以及自动化系统决策(例如设备放置和索引).张量算符(tensor operators),如矩阵乘法和高维卷积 ...

  8. 解读丨从自动驾驶到学习机器学习:科技发展的15大趋势

    科技在明年将会发生巨大的改变.想要了解前沿资讯吗?著名设计公司 frog 做出的这些预测可能会让你了解一些 科技发展趋势.每一个领域都有一个设计师解释全部的细节.哪些东西已经出现在你们的视野中了呢? ...

  9. Jenkins +maven+tomcat自动构建部署(学习笔记三十六)

    https://my.oschina.net/denglz/blog/524154 摘要: jenkins + maven + svn + tomcat 自动部署 jenkins  是做什么用的,如果 ...

最新文章

  1. [SDK文档]SDK简介
  2. Queue.LinkedList
  3. (0007) iOS 开发之Xcode8上传AppStore遇到的TencentOpenApi_IOS_Bundle.bundle
  4. 京东加淘宝,羊毛有点大
  5. python推荐系统-python 简易推荐系统实现
  6. 存在于实数域的微观粒子2-泡利不相容原理
  7. leetcode 209. Minimum Size Subarray Sum | 209. 长度最小的子数组(Java)
  8. memcached 使用 java_java中Memcached的使用(包括与Spring整合)
  9. 读大师的书 说自己的话——《传世经典书丛评注版》邀你来点评
  10. 我在创业公司的开发经验总结
  11. html字体_斗鱼关注人数爬取 | 字体反爬的攻与防
  12. 大学实训_软件毕设_Java入门实战_商场管理系统_Punrain
  13. 图像工作回顾之五:视频检索
  14. leetcode No5 最长回文子串
  15. python基础螺旋线
  16. 台式计算机启动时 每次按f1,电脑开机时总是提示要按F1?云骑士告诉你如何解决...
  17. 内网安全-域横向内网漫游Socks代理隧道技术
  18. [08]ESP32+激光传感器VL53L1x移植与调试(附源码)
  19. 电报电话的原理和作用
  20. 你的密码泄露没?触目惊心的密码泄露该如何查防

热门文章

  1. MySQL错误:The user specified as a definer (XXX@XXX) does not exist
  2. 老男孩第31期杨海学习Linux决心书
  3. 浅谈CIVIL 3D
  4. where,having与 group by连用的区别
  5. 网页设计师必备的35套图标(免费下载)
  6. AIX LV删除后,ORACLE数据库文件全部恢复成功
  7. Software Testing Resource
  8. Unity+KBEngine实战系列1——棋牌(含完整教程与源码)
  9. Git 二分调试法,火速定位疑难Bug!
  10. Winform软件,不要在线程里操作UI