字符串处理-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值来标记以当前节点为后 ...
随机推荐
- Javascript debugger come accross error
Problem: “Unable to attach to the process. Another debugger might be attached to the process.” Solut ...
- iOS推送证书p12转成pem
首先你需要导出p12格式的证书,具体操作请参考如下: 其次你就可以通过在控制台输入如下命令即可转换: openssl pkcs12 -in 你导出的p12证书 -out 你要转换的pem证书 -nod ...
- C++之对象存储空间_对象模型
C++编译器如何完成面向对象理论向计算机程序的转化 #include<stdio.h>//////c++对象模型和结构体一样 class Test { ...
- Google浏览器的缓存文件过大(mega网站导致的)
到选项里清空所有内容也没有用. 后来手动找了一下,原来在这里,存了在这里存了整整10G的缓存: C:\Users\my\AppData\Local\Google\Chrome\User Data\Pr ...
- wchar_t是内置还是别名(亲测有效:wchar_t在windows下是16位整数的别名,在linux等平台下是32位整数的别名。MSVC2008开始默认是/Zc:wchar_t)
接前一篇C++ ABI之名字改编(以Qt为例),继续看看C++名字改编相关的问题. 问题 MSVC 有一对选项/Zc:wchar_t- 与 /Zc:wchar_t控制wchar_t 于是 wchar_ ...
- hibernate HQL查询 2.2
hql(都要在事务中完成)session.beginTransaction();session.getTransaction().commit(); session.beginTransaction( ...
- OGNL逻辑标签,UI标签
逻辑标签 public class IndexAction extends BasicAction{ private static final long serialVersionUID = 1L; ...
- 解析带有命名空间问题web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" ...
- 误mlogc.c:32:23: error: curl/curl.h: No such file or directory
出现以下错误: mlogc.c:32:23: error: curl/curl.h: No such file or directory mlogc.c:1091: error: expected ' ...
- 写一个方法完成如下功能,判断从文本框textbox1输入的一个字符,如果是数字则求该数字的阶乘,如果是小写字条,则转换为大写,大写字符不变,结果在文本框textbox2中显示
窗体设计: 代码: using System; using System.Collections.Generic; using System.ComponentModel; using System. ...