KMP && ACA

KMP:

吼哇!

反正网上教程满天飞,我就不写了。

发个自己写的模板

  /**
freopen("in.in", "r", stdin);
freopen("right.out", "w", stdout);
*/
//// /////////////////////////////
#include <cstdio>
#include <string>
#include <iostream>
using std::string;
const int N = ; int nex[N]; int main() {
freopen("in.in", "r", stdin);
freopen("right.out", "w", stdout);
string s, p;
std::cin >> s >> p; nex[] = ;
for(int i = , j = ; i < p.size(); i++) {
while(j && p[i] != p[j]) {
j = nex[j - ];
}
if(p[i] == p[j]) j++; /// while(j && p[i + 1] == p[j]) j = nex[j - 1];
/// 十分失败的优化,反例:
/// acccc
/// ccc
/// 001 :next
/// 可以看出能匹配两个串,但是这个优化只能算出一个来 nex[i] = j;
} for(int i = , j = ; i < s.size(); i++) {
while(j && s[i] != p[j]) {
j = nex[j - ];
}
if(s[i] == p[j]) j++;
if(j == p.size()) {
printf("%d\n", i - j + );
j = nex[j - ];
}
} for(int i = ; i < p.size(); i++) {
printf("%d ", nex[i]);
} return ;
}

KMP模板 洛谷P3375

例题:

剪花布条

A + B for you again

Period

Milking Grid

业界大毒瘤动物园

AC自动机:

就是KMP上trie,用以解决多串匹配问题。

当我花几天的时间理解KMP之后,AC自动机也就很显然了(这怎么就显然了?)

想当我学KMP满大街找教程,现在学AC自动机教程还没看完就懂了...所以说基础很重要。

大致想象一下就行了。直接发代码吧。

 #include <cstdio>
#include <string>
#include <iostream>
#include <queue>
#include <cstring>
const int N = ; using std::string; struct AC {
int root, tot;
int tr[N][], nex[N], ed[N];
bool vis[N];
AC() {
root = ;
tot = ;
}
void clear() {
for(int i = ; i <= tot; i++) {
nex[i] = ed[i] = ;
for(int j = ; j < ; j++) {
tr[i][j] = ;
}
}
return;
} inline void insert(string x) {
int p = root;
for(int i = ; i < x.size(); i++) {
int f = x[i] - 'a';
if(!tr[p][f]) {
tr[p][f] = ++tot;
}
p = tr[p][f];
}
ed[p]++;
return;
}
void getnex() {
nex[root] = root;
std::queue<int> Q;
Q.push(root);
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int i = ; i < ; i++) {
int y = tr[x][i];
if(y) {
int j = nex[x];
while(j != root && !tr[j][i]) {
j = nex[j];
}
if(tr[j][i] && x != root) {
j = tr[j][i];
}
nex[y] = j;
Q.push(y);
}
}
}
return;
}
int solve(string x) {
int ans = ;
memset(vis, , (tot + ) * sizeof(bool));
for(int i = , j = root; i < x.size(); i++) {
int f = x[i] - 'a';
while(j != root && !tr[j][f]) {
j = nex[j];
}
if(tr[j][f]) {
j = tr[j][f];
}
if(ed[j] && !vis[j]) {
ans += ed[j];
vis[j] = ;
}
}
return ans;
}
}ac; int main() {
int n;
scanf("%d", &n);
string s;
for(int i = ; i <= n; i++) {
std::cin >> s;
ac.insert(s);
}
ac.getnex();
std::cin >> s;
printf("%d", ac.solve(s));
return ;
}

洛谷P3808

 #include <cstdio>
#include <string>
#include <iostream>
#include <queue>
#include <cstring>
const int N = ; using std::string; struct Ans {
string s;
int cnt;
}a[N]; struct AC {
int root, tot;
int tr[N][], nex[N], ed[N];
AC() {
root = ;
tot = ;
}
void clear() {
for(int i = ; i <= tot; i++) {
nex[i] = ed[i] = ;
for(int j = ; j < ; j++) {
tr[i][j] = ;
}
}
tot = ;
return;
} inline void insert(string x, int k) {
int p = root;
for(int i = ; i < x.size(); i++) {
int f = x[i] - 'a';
if(!tr[p][f]) {
tr[p][f] = ++tot;
}
p = tr[p][f];
}
ed[p] = k;
return;
}
void getnex() {
nex[root] = root;
std::queue<int> Q;
Q.push(root);
while(!Q.empty()) {
int x = Q.front();
Q.pop();
for(int i = ; i < ; i++) {
int y = tr[x][i];
if(y) {
int j = nex[x];
while(j != root && !tr[j][i]) {
j = nex[j];
}
if(tr[j][i] && x != root) {
j = tr[j][i];
}
nex[y] = j;
Q.push(y);
}
}
}
return;
}
void solve(string x) {
for(int i = , j = root; i < x.size(); i++) {
int f = x[i] - 'a';
while(j != root && !tr[j][f]) {
j = nex[j];
}
if(tr[j][f]) {
j = tr[j][f];
}
int jj = j;
while(jj != root) {
if(ed[jj]) {
a[ed[jj]].cnt++;
}
jj = nex[jj];
}
}
return;
}
}ac; int main() {
int n;
string x;
while(scanf("%d", &n) && n) {
ac.clear();
for(int i = ; i <= n; i++) {
std::cin >> a[i].s;
ac.insert(a[i].s, i);
}
ac.getnex();
std::cin >> x;
ac.solve(x);
int large = -;
for(int i = ; i <= n; i++) {
large = std::max(large, a[i].cnt);
}
printf("%d\n", large);
for(int i = ; i <= n; i++) {
if(a[i].cnt == large) {
std::cout << a[i].s << std::endl;
}
}
for(int i = ; i <= n; i++) {
a[i].cnt = ;
}
}
return ;
}

洛谷P3796

重点在于getnex()函数。别的依题意稍作修改即可。

第二题有个优化:ed[nex[jj]]可能为0,会额外增加跳的次数。解决办法是搞一个g数组出来表示ed[]不为0的某个nex。

被之前失败的优化经历搞怕了,没用...

KMP与AC自动机的小差异:(在我的模板中)

KMP初始化的nex[0] = 0,而AC自动机的初始化nex[root]  =  root;

KMP中的nex[i]表示最长匹配数,是比下标多1的,而AC自动机中直接指向一个节点。

看毛片就能AC算法的更多相关文章

  1. kmp//呵呵!看毛片算法

    以前刚学的时候迷迷糊糊的,一看就懵圈,前几天捡起来的时候 发现还不会 于是研究了两天,自尊心严重受挫,今天的时候  突然一道灵光迸发,居然 感觉好像懂了,于是又琢磨起来  终于  我懂了  呵呵!   ...

  2. KMP算法再解 (看毛片算法真是人如其名,哦不,法如其名。)

    KMP算法主要解决字符串匹配问题,其中失配数组next很关键: 看毛片算法真是人如其名,哦不,法如其名. 看了这篇博客,转载过来看一波: 原博客地址:https://blog.csdn.net/sta ...

  3. SDUT OJ 数据结构实验之串一:KMP简单应用 && 浅谈对看毛片算法的理解

    数据结构实验之串一:KMP简单应用 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descr ...

  4. 快速字符串匹配一: 看毛片算法(KMP)

    前言 由于需要做一个快速匹配敏感关键词的服务,为了提供一个高效,准确,低能耗的关键词匹配服务,我进行了漫长的探索.这里把过程记录成系列博客,供大家参考. 在一开始,接收到快速敏感词匹配时,我就想到了 ...

  5. AC算法学习笔记

    1.算法流程图 (1)    void Init() 此函数是初始化函数,用来给fail数组和goto数组初始化值. (2)    void GotoFunction(string x) 这个函数的作 ...

  6. [转] 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一网打尽

    字符串模式匹配算法——BM.Horspool.Sunday.KMP.KR.AC算法一网打尽 转载自:http://dsqiu.iteye.com/blog/1700312 本文内容框架: §1 Boy ...

  7. 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法一网打尽

    字符串模式匹配算法——BM.Horspool.Sunday.KMP.KR.AC算法一网打尽 本文内容框架: §1 Boyer-Moore算法 §2 Horspool算法 §3 Sunday算法 §4 ...

  8. 字符串模式匹配算法——BM、Horspool、Sunday、KMP、KR、AC算法

    ref : https://dsqiu.iteye.com/blog/1700312 本文内容框架: §1 Boyer-Moore算法 §2 Horspool算法 §3 Sunday算法 §4 KMP ...

  9. AC算法 及python实现

    零 导言 软件安全课上,老师讲了AC算法,写个博客,记一下吧. 那么AC算法是干啥的呢? ——是为了解决多模式匹配问题.换句话说,就是在大字符串S中,看看小字符串s1, s2,...有没有出现. AC ...

随机推荐

  1. Windows编译OpenCV4Android解决undefined reference to std错误

    注意OpenCV 4.0.1 解决了这个问题请直接下载OpenCV 4.0.1 但是OpenCV 4.0.1作为模块导入Android Studio会有找不到R.styleable的问题 OpenCV ...

  2. MUI 实用教程

    MUI 实用JS教程: https://www.kancloud.cn/benhailong/mui/319751  MUI 实用教程: https://www.kancloud.cn/benhail ...

  3. 解决jest处理es模块

    解决jest处理es模块 问题场景 项目使用jest进行测试时, 当引入外部库是es模块时, jest无法处理导致报错. Test suite failed to run Jest encounter ...

  4. vue.js的手脚架vue-cli项目搭建的步骤

    手脚架是什么? 众所周知,现在的前端项目发展得越渐越大,我们前端程序员要从0开始去搭建一套完整的项目很费时,所以这时候前端工程的手脚架就出现了. 我用得vue-cli也是其中之一,还有其他的我也说不清 ...

  5. mysql的定时器

    mysql定时器是系统给提供了event,而oracle里面的定时器是系统给提供的job.废话少说,下面创建表: create table mytable ( id int auto_incremen ...

  6. SQL Server 2008初次启动

    一.关于安装 SQL Server 数据库的安装,经过自己的安装,总体还是比较容易,没有太多难度,安装包在网上也有很多,在此,就跳过安装的这一步. 二.初次启动SQL Server 安装完成数据库后, ...

  7. 【原】Java学习笔记009 - 阶段测试

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 1.需求:打印如下 ...

  8. Error:Cannot run program "svn" (in directory "E:demo\Hello"): CreateProcess error=2,

    file-->settings-->version controller --> subversion

  9. 我的第一个python web开发框架(23)——代码版本控制管理与接口文档

    书接上一回,小白和老菜聊到代码的版本控制和接口文档 小白:为什么要做版本控制,我不弄版本控制不也完成了项目了吗?要做版本控制不是很麻烦,又要安装服务又要提交代码,代码又不是多人用开发,还要写文档... ...

  10. 【Teradata】扩容操作步骤

    第一章,前期准备(旧系统信息收集) 1.DBScontrol关键信息 DBSCONTROL系统参数是在节点上设置的,其参数直接关系到系统全局,需要慎重设置,新节点的关键参数要与生产库一致或者相容.主要 ...