您的位置:首页 > 其它

[HDU 3065]病毒侵袭持续中[AC自动机][模板题]

2013-08-06 12:08 429 查看
很久没有自己敲一个题了,这道又WA得我内!牛!满!面!啊......不过还是得这样才印象深刻.

记得检查输入是否正确.不要焦躁.

AC了之后感觉忽然有了力量~

题意:给出许多模式串,一个源码,求源码中都有哪些模式串出现了,分别出现几次.

思路:AC_Automation中,注意模式串之间有重叠的情况,就是无论是否匹配到了当前串的末尾,都要借助一个tmp指针往回找一遍,看看别的链上是否有可以匹配的.一直找到根为止.

对于输出要求,首先trie树的尾节点标记id为输入序号,从0开始.同时准备一个结构体数组,按照id顺序存病毒名和出现次数.

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int n;
inline int GetId(char c)
{
return c - 'A';
}
typedef struct virus
{
string name;
int freq;
}virus;
class node{
public:
node *chd[26];
node *fail;
int id;

node(){
memset(chd,0,sizeof(chd));
fail = NULL;
id = -1;
}
};

class AC_Automation
{
public:
node *root;
queue <node*> q;
virus v[1005];

AC_Automation(){
root = new node;
while(!q.empty()) q.pop();
for(int i=0;i<n;i++)
v[i].freq = 0;
}
void insert(string s,int th)
{
node *cur = root;
int len = s.length();
for(int i=0;i<len;i++)
{
int index = GetId(s[i]);
if(!cur->chd[index]) cur->chd[index] = new node;
cur = cur->chd[index];
}
cur->id = th;
v.name = s;
}
void BuildAC()
{
node *cur,*tmp;
q.push(root);
while(!q.empty())
{
cur = q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(cur->chd[i])
{
if(cur == root) cur->chd[i]->fail = root;
else
{
tmp = cur->fail;
while(tmp->fail && !tmp->chd[i]) tmp = tmp->fail;///*
if(tmp->chd[i]) cur->chd[i]->fail = tmp->chd[i];
else cur->chd[i]->fail = root;
}
q.push(cur->chd[i]);
}
}
}
}
void query(string s)
{
node *cur = root,*tmp;///shers
int len = s.length();
for(int i=0;i<len;i++)
{
int index = GetId(s[i]);
if(index<0 ||index>=26)
{
cur = root;//puts("here");
continue;
}
if(cur->chd[index]) cur = cur->chd[index];
else
{
while(cur && !cur->chd[index]) cur = cur->fail;///*
if(!cur) cur = root;
if(cur->chd[index]) cur = cur->chd[index];
}
tmp = cur;
while(tmp->fail)///为了处理相互重叠或相互包含的情况
{
if(tmp->id > -1)
v[tmp->id].freq++;
tmp = tmp->fail;

}
}
}
void PrintRes()
{
for(int i=0;i<n;i++)
{
if(v[i].freq) cout<<v[i].name<<": "<<v[i].freq<<endl;
}
}
};
char pat[52],tar[2000005];

int main()
{
while(scanf("%d",&n)==1)
{
AC_Automation AC;
getchar();
for(int i=0;i<n;i++)
{
gets(pat);
// cout<<"pat "<<pat<<endl;
AC.insert(pat,i);
}
AC.BuildAC();
gets(tar);
// cout<<"tar "<<tar<<endl;
AC.query(tar);

AC.PrintRes();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: