估计在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. HDU 1796 容斥原理 How many integers can you find

    题目连接   http://acm.hdu.edu.cn/showproblem.php?pid=1796 处男容斥原理  纪念一下  TMD看了好久才明白DFS... 先贴代码后解释 #includ ...

  2. SharePoint网站集功能介绍

    SharePoint网站集功能介绍 https://support.office.com/zh-cn/article/%E5%90%AF%E7%94%A8%E6%88%96%E7%A6%81%E7%9 ...

  3. python切片练习

    这块儿没什么难的,细心一点就好 L = [] n = 1 while n <= 99: L.append(n) n = n + 2 print(L) #但是在Python中,代码不是越多越好,而 ...

  4. 玩2k16

    2k是我最喜欢的游戏啦,平时无聊了都会搞两盘.现在到2k16了,玩游戏时碰到一些麻烦,记录便查. 我哥一直说他的电脑玩2K16非常卡,根本玩不了,但是他的电脑配置可比我的高啊,我玩起溜溜地,喊他把配置 ...

  5. struts jsp传值到action,乱码的解决方案

    使用了Struts框架,前台写好了编码为utf-8 <%@ page language="java" contentType="text/html; charset ...

  6. sql server单表导入、导出

    sql server单表导入.导出(通过CSV文件) 导出:直接打开查询分析器查询要导出表的信息(select *  from 表),得到的结果全选,右键另存为 xxx.csv文件  (得到该表的所有 ...

  7. ASP.NET 内置对象涉略

    一.ASP.NET中内置的常用对象的介绍 本文列举了ASP.NET 的八个内置对象,其中前五个是比较常用的. 1.Response Response 对象用于从服务器向用户发送输出的结果. Write ...

  8. 本地机apache配置基于域名的虚拟主机详解

    1.打开apache的httpd.conf文件,找到# Virtual hosts#Include conf/extra/httpd-vhosts.conf这一段把Include conf/extra ...

  9. Eddy's爱好(dfs+容斥)

    Eddy's爱好 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  10. (step5.1.3)hdu 1213( How Many Tables——1213)

    题目大意:输入两个整数n,m.分别表示点数.对点的操作的次数.在接下来的m行中,每行有两个整数a,b.表示a和b是好朋友.(不是好朋友的不能坐在同一个桌子上) .求需要多少张桌子 解题思路:并查集 1 ...