AC自动机

(注:此博不是讲解,只是备忘用的)

多模式串匹配的好东西~

以trie树为保存字符串的载体,在树上建立失配边来进行模式串间的转移,以达到快速匹配的目的。

以 HDU:2222  Keywords Search 为例:

(但有些部分代码设计不太合理,可根据题微调)

(此处采用了建trie图的思想加速,但实际还可以用last数组再度加速)

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define MSZ (1000000)
#define SZ (50)
#define SGSZ (26)
using namespace std;struct TRIE
{char cc;int fail, last;int get, cnt;int next[SGSZ];
};int cTr;
TRIE Tr[MSZ];
// * those are my magic
#define np(p, id) (Tr[p].next[id])
#define fp(p) (Tr[p].fail)
#define lp(p) (Tr[p].last)
#define ct(p) (Tr[p].cnt)
#define gt(p) (Tr[p].get)int T, N;// * get a char's index
inline int index(char cc)
{return cc - 'a';
}inline char opdex(int id)
{return id + 'a';
}// * clear the Trie
void ClearTr()
{for (int i = 0; i <= cTr; i++)Tr[i] = (TRIE){0, 0, 0, 0, 0, 0};return;
}// * add a point into Trie
int AddPTr(int id)
{Tr[++cTr].cc = opdex(id);return cTr;
}// * add a string into Trie
void AddSTr(char s[])
{int p = 0, l = strlen(s);for (int i = 0; i < l; i++){int id = index(s[i]);if (!np(p, id))np(p, id) = AddPTr(id);p = np(p, id); // * Magic part , careful !
    }ct(p)++, lp(p) = p;return;
}void FailAc()
{queue<int> Q;for (int id = 0; id < SGSZ; id++)if (np(0, id))Q.push(np(0, id));while (!Q.empty()){int p = Q.front();Q.pop();for (int id = 0; id < SGSZ; id++){int tp = fp(p);while (tp && !np(tp, id))tp = fp(tp);if (np(p, id)){Q.push(np(p, id));fp(np(p, id)) = np(tp, id);lp(np(p, id)) = ct(np(tp, id)) ? np(tp, id) : lp(np(tp, id));}elsenp(p, id) = np(tp, id);}}return;
}int FindAc(char ms[])
{int p = 0, l = strlen(ms), sum = 0;for (int i = 0; i < l; i++){int id = index(ms[i]);p = np(p, id);int tp = p;while (tp){if (gt(tp))break;gt(tp) = 1;if (ct(tp))sum += ct(tp);tp = lp(tp);}}return sum;
}int main()
{char s[SZ], ms[MSZ];scanf("%d", &T);while (T--){scanf("%d", &N);ClearTr();for (int i = 1; i <= N; i++){scanf("%s", s);AddSTr(s);}FailAc();scanf("%s", ms);printf("%d", FindAc(ms));}return 0;
}

 寻找失配边的fail函数:

...

void FailAc()
{queue<int> Q;for (int id = 0; id < SGSZ; id++)if (np(0, id))Q.push(np(0, id));while (!Q.empty()){int p = Q.front();Q.pop();for (int id = 0; id < SGSZ; id++){int tp = fp(p);while (tp && !np(tp, id))tp = fp(tp);if (np(p, id)){Q.push(np(p, id));fp(np(p, id)) = np(tp, id);lp(np(p, id)) = ct(np(tp, id)) ? np(tp, id) : lp(np(tp, id));}elsenp(p, id) = np(tp, id);}}return;
}

寻找匹配串数量的find函数:

包括fail函数,一定要记住一些明显的优化,比如trie图转化,get标记,last记录上个单词节点。

int FindAc(char ms[])
{int p = 0, l = strlen(ms), sum = 0;for (int i = 0; i < l; i++){int id = index(ms[i]);p = np(p, id);int tp = p;while (tp){if (gt(tp))break;gt(tp) = 1;if (ct(tp))sum += ct(tp);tp = lp(tp);}}return sum;
}

清空和加入节点:(以下是Tire树操作)

这是一种很蠢的写法,实际中节点可以直接删除(如用memset清空,不过可能会卡)。

// * add a point into Trie
int AddPTr(int id)
{Tr[++cTr].cc = opdex(id);return cTr;
}// * add a string into Trie
void AddSTr(char s[])
{int p = 0, l = strlen(s);for (int i = 0; i < l; i++){int id = index(s[i]);if (!np(p, id))np(p, id) = AddPTr(id);p = np(p, id); // * Magic part , careful !
    }ct(p)++, lp(p) = p;return;
}

 将字符转化成编号和反转化的函数:

这是为那些写trie树却不会指针的同学们准备的,将每个字符转化成唯一对应的下标。

// * get a char's index
inline int index(char cc)
{return cc - 'a';
}inline char opdex(int id)
{return id + 'a';
}

宏黑魔法++。

转载于:https://www.cnblogs.com/Ztraveler/p/6933512.html

【模版】(旧)AC自动机相关推荐

  1. HDU2896(AC自动机模版题)

    AC自动机模版题: 方法一:超时 #include<iostream> #include<algorithm> #include<cstring> #include ...

  2. hdu 2222 AC 自动机 模版(数组实现)

    AC 自动机 模版 原文匹配查找时讲错了,其他都挺好(原文博主知错懒得改 t个样例,n个单词,一个文本串,求文本串中单词出现的次数. 若给出单词ab,ab 文本ab,匹配数为2 若给出 n个不重复的单 ...

  3. HDU2222(AC自动机模版题)

    AC自动机是Trie树和KMP的结合物,但是其实KMP在这里体现了思想,而Trie树才是最重要的,要想学懂AC自动机,学习Trie树是必须的,这些是自己在学习AC自动机的个人看法,我也是在网上学习了大 ...

  4. 【HDU2896】病毒侵袭——ac自动机

    网上很多代码都略显繁琐,看了一下yy dalao的代码感觉很好,但他懒得打题解(好吧我也是 以0为根节点的话,我把yy的一段代码删了改用fail[c]=x==0?0:ch[fail[x]][i];来实 ...

  5. hdu 2222 Keywords Search(ac自动机)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:给你一系列子串,再给你一个主串问你主串一共有几个匹配子串 原来使用字典树写的但数据有点大T ...

  6. AC自动机——Uva 11468 子串

    题目链接:http://vjudge.net/contest/142513#problem/A 题意:给出一些字符和各自对应的选择概率,随机选择L次后将得到一个长度为L的随机字符串S.给出K个模版串, ...

  7. 字符串处理 —— AC 自动机

    [概述] KMP 算法用于解决长文本的单模板匹配问题,字典树用于解决单个单词(短文本)多模板匹配问题,而 AC 自动机用于解决的是长文本的多模板匹配问题,其是以 trie 树的结构为基础,结合 KMP ...

  8. 【距离GDOI:128天】【POJ2778】DNA Sequence(AC自动机+矩阵加速)

    已经128天了?怎么觉得上次倒计时150天的日子还很近啊 ....好吧为了把AC自动机搞透我也是蛮拼的..把1030和这道题对比了无数遍...最终结论是...无视时间复杂度,1030可以用这种写法解. ...

  9. HiHocoder 1036 : Trie图 AC自动机

    Trie图 先看一个问题:给一个很长很长的母串 长度为n,然后给m个小的模式串.求这m个模式串里边有多少个是母串的字串. 最先想到的是暴力O(n*m*len(m)) len(m)表示这m个模式串的平均 ...

  10. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

最新文章

  1. java常见集合及其用途
  2. 【枚举】【SPFA】Urozero Autumn Training Camp 2016 Day 5: NWERC-2016 Problem I. Iron and Coal
  3. 1500+ FPS!目前最快的CNN人脸检测算法开源
  4. 在C#中利用Keep-Alive处理Socket网络异常断开的方法
  5. 推荐 | 8 个 SpringBoot 精选项目
  6. 这些新技术你们都知道吗?成功收获美团,小米安卓offer
  7. 日期 java cal,日期系列教材 (三)- 如何使用Java的Calendar类
  8. 作者:​林旺群(1983-),男,博士,北京系统工程研究所助理研究员。
  9. VB 迅雷下载地址解密函数
  10. 抛弃jQuery 深入原生的JavaScript
  11. 转载 分布式协调技术 分布式锁
  12. JAVA电子书大礼包
  13. 临床试验数据管理系统
  14. cad沿线插入块 lisp_我有一组数有十几万个坐标点,如何利用lisp程序快速导入CAD中,并可以快速处理!...
  15. 心率检测实现报告(一)
  16. 【Python小工具】若干图片合并生成动态图(.gif)
  17. 在总账模块结账的时候提示总账和明细账对账不平结不了账
  18. iOS创建沙盒账号的步骤和注意事项
  19. 网站关键词优化该怎么做?
  20. 增值税发票二维码解析

热门文章

  1. php刷新显示不一样的语录,JavaScript_js每次Title显示不同的名言,每次都有不同的名言出来。 实 - phpStudy...
  2. vant 时间选择的用法
  3. ElasticSearch7.3学习(二十六)----搜索(Search)参数总结、结果跳跃(bouncing results)问题解析
  4. 学生党还是不当月光族舒服
  5. Sint at magni ducimus veniam dolores eaque volNobis harum mollitia nulla laboriosam dolore.uptatum.
  6. web服务器系统事件日志,web 服务器的系统事件日志
  7. 在java中类的标志是什么车_JAVA写一个汽车类,属性:品牌;车长;颜色;价格;方法:跑的方法...
  8. 元宇宙商标现在都怎么样了
  9. python 实现软件更新
  10. 什么是.bak文件?探索编程中的备份文件