博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
luogu3769 【模板】AC自动机(加强版)
阅读量:4318 次
发布时间:2019-06-06

本文共 2626 字,大约阅读时间需要 8 分钟。

题目大意:有N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。

对每个模式串建立一个Trie树。定义一个节点的Fail指针如下:如果节点x表示模式串a中字符a[i],x->Fail表示模式串b中字符b[j],则b[0,j]该前缀能在a[0,i]中找到与其相等的后缀。匹配时,沿trie树去匹配原串。如果trie树中当前节点cur->Next[i]==NULL,则说明当前所选择的匹配模式串不合适,由于前缀后缀的相等关系,令cur=cur->Fail转移到另一个模式串的前缀的最后一个字符表示的节点继续匹配。当前模式串的一个字符如果匹配成功,还要遍历一下cur的Fail,因为cur->Fail节点所表示的前缀可能便是整个字符串,这时便要将那些节点Sum++。

构造Fail指针方法:已知cur->Fail,设置cur->Next[i]->Fail。BFS遍历cur->Fail,如果Fail节点的Next[i]不为空,则将cur->Next[i]->Fail设为它,否则继续遍历cur->Fail->Fail,表示前缀后缀长度减小后能否匹配着。再不行就匹配到树根。

#include 
#include
#include
#include
#include
#include
using namespace std;#define Ord(c) c-'a'const int MAX_NODE = 5e5 + 1, MAX_SLEN = 1e6 + 1, MAX_CHAR = 26, MAX_P = 200, MAX_PLEN = 80;struct AC{ char S[MAX_SLEN], P[MAX_P][MAX_PLEN]; int _pCnt; struct Node { int Sum; int Cnt; Node *Next[MAX_CHAR], *Fail; Node():Sum(0),Cnt(0){} }_nodes[MAX_NODE]; Node *Root, *Tail[MAX_P]; int _vCount; void Init(int pCnt) { Root = _nodes; memset(_nodes, 0, sizeof(_nodes)); _pCnt = pCnt; _vCount = 1; } Node *NewNode() { return _nodes + _vCount++; } Node* BuildTrie(char *s) { int len = strlen(s); Node *cur = Root; for (int p = 0; p < len; p++) { if (cur->Next[Ord(s[p])]) cur = cur->Next[Ord(s[p])]; else cur = cur->Next[Ord(s[p])] = NewNode(); } cur->Sum++; return cur; } void SetFail() { queue
q; q.push(Root); while (!q.empty()) { Node *cur = q.front(); q.pop(); for (int i = 0; i < MAX_CHAR; i++) { if (cur->Next[i]) { Node *temp = cur->Fail; while (temp) { if (temp->Next[i]) { cur->Next[i]->Fail = temp->Next[i]; break; } temp = temp->Fail; } if (!temp) cur->Next[i]->Fail = Root; q.push(cur->Next[i]); } } } } void Find() { int len = strlen(S); Node *cur = Root; for (int p = 0; p < len; p++) { while (cur != Root && !cur->Next[Ord(S[p])]) cur = cur->Fail; if (!(cur = cur->Next[Ord(S[p])])) cur = Root; for (Node *temp = cur; temp != Root; temp = temp->Fail) if (temp->Sum) temp->Cnt++; } } void Proceed() { for (int i = 0; i < _pCnt; i++) Tail[i] = BuildTrie(P[i]); SetFail(); Find(); }}g;int main(){#ifdef _DEBUG freopen("c:\\noi\\source\\input.txt", "r", stdin);#endif int pCnt; while (scanf("%d", &pCnt) && pCnt) { g.Init(pCnt); for (int i = 0; i < pCnt; i++) scanf("%s", g.P[i]); scanf("%s", g.S); g.Proceed(); int ans = 0; for (int i = 0; i < pCnt; i++) ans = max(ans, g.Tail[i]->Cnt); printf("%d\n", ans); for (int i = 0; i < pCnt; i++) if (g.Tail[i]->Cnt == ans) printf("%s\n", g.P[i]); } return 0;}
View Code

 

转载于:https://www.cnblogs.com/headboy2002/p/8453757.html

你可能感兴趣的文章
通过镜像下载Android系统源码
查看>>
python字符串格式化 %操作符 {}操作符---总结
查看>>
windows 不能在 本地计算机 启动 Apache
查看>>
iOS开发报duplicate symbols for architecture x86_64错误的问题
查看>>
Chap-6 6.4.2 堆和栈
查看>>
【Java学习笔记之九】java二维数组及其多维数组的内存应用拓展延伸
查看>>
C# MySql 连接
查看>>
sk_buff Structure
查看>>
oracle的级联更新、删除
查看>>
多浏览器开发需要注意的问题之一
查看>>
Maven配置
查看>>
HttpServletRequest /HttpServletResponse
查看>>
SAM4E单片机之旅——24、使用DSP库求向量数量积
查看>>
从远程库克隆库
查看>>
codeforces Unusual Product
查看>>
hdu4348 - To the moon 可持久化线段树 区间修改 离线处理
查看>>
springMVC中一个class中的多个方法
查看>>
Linux系统安装出错后出现grub rescue的修复方法
查看>>
线段树模板整理
查看>>
[iOS问题归总]iPhone上传项目遇到的问题
查看>>