字符串处理-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值来标记以当前节点为后 ...
随机推荐
- CDLinux环境下WiFi密码破解
> 准备好所需软件以及上篇教程中使用Fbinstool制作的可启动U盘 2 > 解压CDLinux-0.9-spring-0412.iso到U盘的根目录 如图 3 > 打开fbin ...
- 赵雅智:service_startService生命周期
案例演示 布局文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xm ...
- Oracle游标循环更新数据案例
declare v_XTXMBH number; v_ZJZJZJRQ varchar2(40); cursor c_job is SELECT XT.XTXMBH AS XTXMBH, QJ.ZJZ ...
- React Native-目前最火的前端技术?
做为一名产品经理,你是否遇到过这样的窘境,“帮我把字体调成 16号呗,颜色变成 #FFFF00FF,老大说这里最好改一下”,作为一名 app 的开发只能无奈但心里窃喜的告诉你,“只能等下个版本了,必须 ...
- When to use HTML Helper?
HTML Helper Single or closely related HTML elements(template) Simpler,low level logic for displaying ...
- C++日期和时间
C++ 日期 & 时间 C++ 标准库没有提供所谓的日期类型.C++ 继承了 C 语言用于日期和时间操作的结构和函数.为了使用日期和时间相关的函数和结构,需要在 C++ 程序中引用 <c ...
- 模仿jquery的一些实现 第二版
具体如下: //w作为window的形参,就表示window (function(w) { // 定义一个全局的window.wyl变量,就类似于jquery里的$,Jquery对象 w.wyl; / ...
- vs2010中iostream.h出错
使用 #include <iostream> using namespace std; 替代 VS2010删除了所有非标准库,保留了C++标准库,iostream.h是以前旧版的库,VS2 ...
- Qt在各平台上的搭建qt-everywhere
Qt for windows7-64bit 在电脑上安装mingw(搜索mingw for windows),将C:\MinGW\bin添加进环境变量,打开命令行输入gcc --version和g++ ...
- Windows Phone 8初学者开发—第3部分:编写第一个Windows Phone 8应用程序
原文 Windows Phone 8初学者开发—第3部分:编写第一个Windows Phone 8应用程序 原文地址: http://channel9.msdn.com/Series/Windows- ...