估计在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自动机的更多相关文章

  1. 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 ...

  2. HDU-2222 Keywords Search 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-2222 题意 给一些关键词,和一个待查询的字符串 问这个字符串里包含多少种关键词 思路 AC自动机模版题咯 注意一般情况 ...

  3. 字符串(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 ...

  4. HDU-2896 病毒侵袭 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-2896 题意 中文题 给一些关键词和一个字符串,问字符串里包括了那几种关键词 思路 直接套模版 改insert方法,维护 ...

  5. HDU-3065 病毒侵袭持续中 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-3065 题意 跟上一道题是几乎一模一样,这次是统计关键词的出现次数 一个相当坑的地方,注意多组样例 思路 套模版 改in ...

  6. 字符串(AC自动机):COCI 2015 round 5 divljak

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAy0AAANaCAIAAAALVTQoAAAgAElEQVR4nOy9X2hbx773PXfrQgQjDq

  7. 字符串:AC自动机

    给出一个字典和一个模式串,问模式串中出现几个字典中的单词 最后一行是大串,之前输入的是小串 #include<iostream> #include<cstdio> using ...

  8. 多模字符串匹配算法之AC自动机—原理与实现

    简介: 本文是博主自身对AC自动机的原理的一些理解和看法,主要以举例的方式讲解,同时又配以相应的图片.代码实现部分也予以明确的注释,希望给大家不一样的感受.AC自动机主要用于多模式字符串的匹配,本质上 ...

  9. poj 1625 (AC自动机好模版,大数好模版)

    题目 给n个字母,构成长度为m的串,总共有n^m种.给p个字符串,问n^m种字符串中不包含(不是子串)这p个字符串的个数. 将p个不能包含的字符串建立AC自动机,每个结点用val值来标记以当前节点为后 ...

随机推荐

  1. 初试PL/SQL并行编程

    -----------------------------Cryking原创------------------------------ -----------------------转载请注明出处, ...

  2. Android中获取系统的时间

    activity代码 public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); set ...

  3. 概率图模型(PGM)学习笔记(三)模式判断与概率图流

    我们依旧使用"学生网络"作为样例,如图1. 图1 首先给出因果判断(Causal Reasoning)的直觉解释. 能够算出来 即学生获得好的推荐信的概率大约是0.5. 但假设我们 ...

  4. 解决外贸电商难题,PayPal中国外贸电商大会圆满礼成

        在全球经济一体化的背景下,越来越多的中国企业将目光转移到了海外.对中国的企业而言,要想将生意做到海外大致有两种方法可供选择,一是到海外设立分支机构或者分公司,二是通过外贸电子商务平台实现交易. ...

  5. 记一次排查log4net 不输出日志的解决过程

    最近发现log4net 不输出日志了,重点排查几个地方,发现都没有问题. 1.[assembly: log4net.Config.XmlConfigurator(ConfigFile = " ...

  6. if和switch的区别,循环的for 和while的区别, 字符串常用的7种方法

    相同点: 都是用于多重选择 不同点: 多重IF没有switch选择结构的限制,特别适合变量处于某个连续区间的情况 switch只能处理等值条件判断的情况,而且条件必须是整型变量或者字符串变量 字符串的 ...

  7. django中间件templates写法

    def templates_context_process(request): from django.contrib.sites.models import Site from accounts.m ...

  8. Regex阅读笔记(五)java操作篇

    首先一个demo程序 Java的正则表达式包为java.util.regex,主要是使用其中的Pattern和Matcher. groupCount方法时候都可调用,而大多数方法都必须在匹配尝试成功之 ...

  9. Regex阅读笔记(三)之固化分组

    符号:?> 使用?>的匹配与正常的匹配无区别,但是如果匹配进行到此结构之后,此结构体的所有备用状态都会放弃,也就是括号内的子表达式中未尝试过的备用状态都不复存在了. 例如'(\.\d\d( ...

  10. Mac平台编译mupdf-qt的开源项目

    How to compile mupdf-qt Compile on Linux Install tools and thirdparty libraries You should install s ...