字符串处理-AC自动机
估计在OJ上刷过题的都会对AC自动机这个名词很感兴趣,同样,记得去年ACM暑期集训的时候,在最后讲到字符串部分,听说了这个算法的名字之后就对于它心向往之,AC正好是Accept的简称,字面意义上的理解是一个可以让题目自动AC的东西,那这是有多厉害!很多次和同学开玩笑,都会提起这个名词。不过其实毕竟只是个字符串处理的算法,真正学起来还是费了不少力。
百度一下就会看到一个模版题:
hdu 2222 Keywords Search
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node{
node *fail;
node *next[];
int count;
node()
{
fail=NULL;
count=;
memset(next,NULL,sizeof(next));
}
}*q[];
char keyword[];
char text[];
int head,tail;
//建树
void insert(char str[],node *root)
{
node *p=root;
int i=,index=;
while(str[i])
{
index=str[i]-'a';
if(p->next[index]==NULL)
{
p->next[index]=new node();
}
p=p->next[index];
i++;
}
p->count++;
}
/*设这个节点上的字母为C,沿着他父亲的失败指针走,
直到走到一个节点,他的儿子中也有字母为C的节点。
然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,
那就把失败指针指向root。具体操作起来只需要:先把root加入队列(root的失败指针指向自己或者NULL),
这以后我们每处理一个点,就把它的所有儿子加入队列,队列为空。*/
void bulidAC(node *root)
{
int i;
root->fail=NULL;
q[head++]=root;
while(head!=tail)
{
node *temp=q[tail++];//元素出栈,
node *p=NULL;
for(i=;i<;i++)
{
if(temp->next[i]!=NULL)//处理出栈元素的所有的子元素的fail指针
{
if(temp==root)temp->next[i]->fail=root;//根元素的下一级置失败指针
else
{
p=temp->fail;//父元素的失败指针
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(p==NULL)temp->next[i]->fail=root;//如果最终指向空,当前子元素指根元素
}
q[head++]=temp->next[i];
}
}
}
}
/*
(1)当前字符匹配,表示从当前节点沿着树边有一条路径可以到达目标字符,
此时只需沿该路径走向下一个节点继续匹配即可,目标字符串指针移向下个字符继续匹配;
(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配,
匹配过程随着指针指向root结束。重复这2个过程中的任意一个,直到模式串走到结尾为止。*/
int match(node *root)
{
int i=,cnt=,index;
node *p=root;
while(text[i])
{
index=text[i]-'a';
while(p->next[index]==NULL&&p!=root)//当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配
p=p->fail;
p=p->next[index];
p=(p==NULL)?root:p;
node *temp=p;
while(temp!=root&&temp->count!=-)
{
cnt+=temp->count;
temp->count=-;
temp=temp->fail;
}
i++;
} return cnt;
}
int main()
{
int n,t;
scanf("%d",&t);
while(t--){
head=tail=;
node *root=new node();
scanf("%d",&n);
getchar();
while(n--){
gets(keyword);
insert(keyword,root);
}
bulidAC(root);
scanf("%s",text);
printf("%d\n",match(root));
}
system("Pause");
return ;
}
hdu 2222
这个题是从家到厦门之前A的最后一个题
题目分三个步骤:
1.建Trie树。通过将keyword全部贴到这个树上。
2.建失败指针。原则是沿着父节点的失败指针往上寻到某个节点的儿子和当前结点字母相同即将该节点的失败指针赋给该节点。
3.匹配。
1.若当前结点无法继续匹配,则沿着失败指针去找到一个可以匹配的结点
2.到某个可以匹配的结点,要一直沿着失败指针往上找到根节点未知
对于abcd,bc两个keyword,abcde为匹配串,如果没有第二步,则只会输出1,即到d匹配完结束,只有失败指针向上寻找才可以将cd找出。
代码基本上是对着模版拍的,也大致理解了,看代码真不容易。。于是今天本想趁热打铁,再来一道简单的题练练手,结果被坑了一个下午。
hdu 2896 病毒侵袭
#include<stdio.h>
#include<string.h>
#include<stdlib.h> struct node{
node *fail;
node *next[];
int count;
int number;
node()
{
fail=NULL;
count=;
memset(next,NULL,sizeof(next));
number=;
}
}*queen[];
char code[];
char text[];
int head,tail;
int num[],bound=;
void insert(node *root,char str[],int num)
{
node *p=root;
int i=,index=;
while(str[i])
{
index=str[i]-' ';
if(p->next[index]==NULL)
{
p->next[index]=new node();
}
p=p->next[index];
i++;
}
p->count++;
p->number=num;
}
void buildAC(node *root)
{
head=tail=;
queen[head++]=root;
root->fail=NULL;
while(head!=tail)
{
node *now=queen[tail++];
for(int i=;i<;i++)
{
if(now->next[i]!=NULL)
{ if(now==root){now->next[i]->fail=root;}
else
{
node *temp=now->fail;
while(temp!=NULL)
{
if(temp->next[i]!=NULL)
{now->next[i]->fail=temp->next[i];
break;
}
temp=temp->fail;
}
if(temp==NULL)
now->next[i]->fail=root;
}
queen[head++]=now->next[i];
}
} }
}
int match(char str[],node *mid)
{ int flag=;
int i=,index=;
int cnt=;
node *p=mid;
while(str[i])
{
index=str[i]-' ';
while(p->next[index]==NULL&&p!=mid)
p=p->fail;
p=p->next[index];
p=(p==NULL)?mid:p;
node *temp=p;
while(temp!=mid)
{
cnt+=temp->count;
if(temp->count>)
{
num[bound++]=temp->number;
}
temp=temp->fail;
}
i++;
}
return cnt;
}
int compare(const void*a,const void*b){return *(int *)a-*(int *)b;}
int main()
{
int N,M;
int ans=;
node *root=new node();
scanf("%d",&N);
for(int i=;i<N;i++)
{
scanf("%s",code);
insert(root,code,i+);
} buildAC(root); scanf("%d",&M);
for(int i=;i<M;i++)
{
int res;
memset(num,,sizeof(num));
bound=;
node *every=root;
memset(text,,sizeof(text));
scanf("%s",text);
res=match(text,every);
if(res!=)
{
printf("web %d:",i+);
qsort(num,bound,sizeof(int),compare);
for(int j=;j<bound;j++)
printf(" %d",num[j]);
printf("\n");
ans++;
}
}
printf("total: %d\n",ans);
return ;
}
hdu 2896
这个题目基本也算模版题,但客观情况是与上一题相比变化在与多组需要匹配的文本与ASCII字符集的范围改变了。
这两个问题尤其是后面一个困扰了很久,按照26个字母,造成数组越界6次而不明所以。
而另外一个纠结的问题则是指针,结构体指针,函数指针传值这些东西之间的关系。后来将count变为-1这个判断去掉,避开了这个问题。
从家回学校,中间又隔了不少天,在火车上收到了中科院面试的短信,有点安心,又有点担心,昨天回学校在宿舍待了一天,没啥作为,反而是装了dota2,被虐了好多局。囧,今天下午在宿舍调了一下午AC自动机代码,对于6号的面试也不一定有什么帮助,而要准备的东西还有很多。继续加油吧。
字符串处理-AC自动机的更多相关文章
- 2017ACM暑期多校联合训练 - Team 8 1006 HDU 6138 Fleet of the Eternal Throne (字符串处理 AC自动机)
题目链接 Problem Description The Eternal Fleet was built many centuries ago before the time of Valkorion ...
- HDU-2222 Keywords Search 字符串问题 AC自动机
题目链接:https://cn.vjudge.net/problem/HDU-2222 题意 给一些关键词,和一个待查询的字符串 问这个字符串里包含多少种关键词 思路 AC自动机模版题咯 注意一般情况 ...
- 字符串(AC自动机):HDU 5129 Yong Zheng's Death
Yong Zheng's Death Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/O ...
- HDU-2896 病毒侵袭 字符串问题 AC自动机
题目链接:https://cn.vjudge.net/problem/HDU-2896 题意 中文题 给一些关键词和一个字符串,问字符串里包括了那几种关键词 思路 直接套模版 改insert方法,维护 ...
- HDU-3065 病毒侵袭持续中 字符串问题 AC自动机
题目链接:https://cn.vjudge.net/problem/HDU-3065 题意 跟上一道题是几乎一模一样,这次是统计关键词的出现次数 一个相当坑的地方,注意多组样例 思路 套模版 改in ...
- 字符串(AC自动机):COCI 2015 round 5 divljak
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAy0AAANaCAIAAAALVTQoAAAgAElEQVR4nOy9X2hbx773PXfrQgQjDq
- 字符串:AC自动机
给出一个字典和一个模式串,问模式串中出现几个字典中的单词 最后一行是大串,之前输入的是小串 #include<iostream> #include<cstdio> using ...
- 多模字符串匹配算法之AC自动机—原理与实现
简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上 ...
- poj 1625 (AC自动机好模版,大数好模版)
题目 给n个字母,构成长度为m的串,总共有n^m种.给p个字符串,问n^m种字符串中不包含(不是子串)这p个字符串的个数. 将p个不能包含的字符串建立AC自动机,每个结点用val值来标记以当前节点为后 ...
随机推荐
- C++类成员常量
由于#define 定义的宏常量是全局的,不能达到目的,于是想当然地觉得应该用const 修饰数据成员来实现.const 数据成员的确是存在的,但其含义却不是我们所期望的.const 数据成员只在某个 ...
- 关于js闭包是否真的会造成内存泄漏(转载)
闭包是一个非常强大的特性,但人们对其也有诸多无解.一种危言耸听的说法是闭包会造成内存泄露. 局部变量本来应该在函数退出的时候被解除引用,但如果局部变量被封闭在闭包形成的环境中,那么这个局部变量就能一直 ...
- Session、SessionId和Cookie的关系
Session是保存在服务器中的,SessionId是保存在Cookie中的. 当用户·登录时候,系统会将"用户名"和"密码"保存到Session中,系统会给每 ...
- codeforces 559A(Gerald's Hexagon)
Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description Gera ...
- ViewFilpper
package com.example.suneyaenews; import java.util.ArrayList; import java.util.HashMap; import java.u ...
- 字符串-06. IP地址转换(20)
#include<iostream> #include<string> #include<cmath> using namespace std; int main( ...
- xml校验问题
struts2使用xml校验 按照书本输入dtd约束文件 "-//OpenSymphony Group//XWork Validator 1.0.2//EN""http: ...
- Uva 1103 Ancient Messages
大致思路是DFS: 1. 每个图案所包含的白色连通块数量不一: Ankh : 1 ; Wedjat : 3 ; Djed : 5 ; Scarab : 4 ; Was : 0 ; Ak ...
- 数据结构——AVL平衡树
1.是二叉搜索树(Binary Search Tree) 2.树和所有左右子树高度之差为-1,0,1 平衡因子(balance factor) =右子树高度-左子树高度 平衡化旋转: 1.从插入位置向 ...
- hdu 4737
题目链接 直接暴力,或运算只会越来越大 #include <cstdio> #include <cstring> using namespace std; #define N ...