您的位置:首页 > 其它

HDU 3695:Computer Virus on Planet Pandora(AC自动机裸题,数组实现AC自动机)

2017-08-15 20:05 543 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3695

题目意思,给出n个模式串和一个文本串,求n个模式串在文本串正串,和反向串中出现的个数。

AC自动机裸题,把文本串在AC自动机上跑一遍,统计一下有多少模式串出现在正着的文本串,

然后将文本串逆序,再在AC自动机上跑一边,统计一下有多少模式串出现在反着的文本串。

不能用动态链表写,开始的时候用动态链表写,TLE了。静态链表没试过,不知道能不能过。

不过动态链表TLE后,我直接用数组写,活生生对着链表的代码改成数组形式的,差点没看晕过去。

不过完美AC了。

AC代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>

using namespace std;

const int allSon = 26;
int node[500000][allSon]; ///字典树节点
int fail[500000]; ///fail指针
int num[500000]; ///以某个节点结尾的单词数
char patten[1010]; ///用来存放模式串
char text[5100010]; ///用来存放文本串
char str[5100010];
int ans; ///放答案
int id; ///给节点编号
///将模式串插入到字典树
void insertPatten()
{
int p = 0;
int index = 0;
while(patten[index]!='\0')
{
int uppercase = patten[index]-'A';
if(node[p][uppercase]==-1) ///对应的儿子不存在
{
memset(node[id],-1,sizeof(node[id]));
num[id] = 0;
fail[id] = -1; ///fail指针置-1代表空
node[p][uppercase] = id++; ///相应的位置放置节点编号
}
p = node[p][uppercase];
index++;
}
num[p]++;
}
///找失败指针,构造AC自动机
void build_AC_automaton()
{
queue<int>qu;
int p = 0; ///最开始指向根节点
qu.push(p);
while(!qu.empty())
{
p = qu.front(); ///出队节点编号
qu.pop();
for(int i = 0; i < allSon; i++)
{
if(node[p][i] != -1) ///看看这个孩子存不存在
{
if(p==0) ///p是根节点
{
fail[node[p][i]] = 0; ///节点的fail指针指向根
}
else
{
int temp = fail[p];
while(temp != -1)
{
if(node[temp][i] != -1)
{
fail[node[p][i]] = node[temp][i];
break;
}
temp = fail[temp];
}
if(temp == -1)
{
fail[node[p][i]] = 0;
}
}
qu.push(node[p][i]);
}
}
}
}
///在AC自动机中进行多模式匹配
void find_in_AC_automaton()
{
int p = 0; ///根节点
int index = 0;
while(text[index]!='\0')
{
int uppercase = text[index]-'A';
while(node[p][uppercase]==-1 && p!=0)
p = fail[p];
p = node[p][uppercase];
if(p == -1) p = 0;
int temp = p;
while(temp!=0 && num[temp]!=-1)
{
ans += num[temp];
num[temp] = -1;
temp = fail[temp];
}
index++;
}
}
///输入文本串
void inputText()
{
scanf("%s",str);//puts(str);
int res = 0;
int pos = 0;
bool flag = false;
int len = strlen(str);
for(int i = 0; i < len; i++)
{
if(str[i]>='A' && str[i]<='Z')
{
if(flag)
{
while(res--)
{
text[pos++] = str[i];
}
}
else text[pos++] = str[i];
}
if(str[i]=='[') flag = true;
if(str[i]>='0' && str[i]<='9') res = res*10+(str[i]-'0');
if(str[i]==']')
{
res = 0;
flag = false;
}
}
text[pos] = '\0';///puts(text);
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(node[0],-1,sizeof(node[0])); ///0号节点是空节点
num[0] = 0;
fail[0] = -1;
id = 1;
for(int i = 0; i < n; i++)
{
scanf("%s",patten);
insertPatten();
}
inputText();
build_AC_automaton();
ans = 0;
find_in_AC_automaton();
int len = strlen(text);
reverse(text,text+len); ///反转一下求一次。
find_in_AC_automaton();
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: