题目大意:给出n个病毒特征和目标网站源码,让找出有多少种病毒出现过,对于出现过的病毒,纪录出现了多少次。
分析:和 HDU2896 差不多,在构造tire树的过程中纪录每个病毒的编码,我们可以创建一个病毒结构体来纪录病毒的输入次序,以及病毒特征码和出现次数,然后在询问过程中可以直接按编号来纪录每一种特征码的病毒出现的次数,最后把出现次数不为0的特征码输出即可。需要注意的是,本题病毒的特征码全是大写字母,但目标网站是所有可见的ASC代码,如果我们在建树的过程中用的是每一种病毒的特征码减去‘A',那么在询问的时候就要先判断当前字符是否为大写字母了。
实现代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
#define son_num 26
#define maxn 2000005
struct nodev //创建病毒结构体
{
char name[55]; //病毒名字
int num; //病毒出现的次数
}virus[1010];
char web[maxn];
struct node
{
int code;
int terminal;
node *fail;
node *next[son_num];
node()
{
fail=NULL;
code=0;
terminal=0;
memset(next,NULL,sizeof(next));
}
};
node *que[maxn];
//构建Tire树
void insert(node *root,char *str,int x) //x为该病毒的编号
{
node *p=root;
int i=0,index;
while(str[i])
{
index=str[i]-'A';
if(p->next[index]==NULL)
p->next[index]=new node();
p=p->next[index];
i++;
}
p->code=x;
p->terminal=1;
}
//寻找失败指针
void build_fail(node *root)
{
int head=0,tail=0;
root->fail=NULL;
que[head++]=root;
while(head!=tail)
{
node *temp=que[tail++];
node *p=NULL;
for(int i=0;i<son_num;i++)
{
if(temp->next[i]!=NULL)
{
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;}
que[head++]=temp->next[i];
}
}
}
}
//询问主串中含有多少个关键字
void query(node *root,char *str)
{
int i=0,cnt=0,index,len;
len=strlen(str);
node *p=root;
while(str[i])
{
if(isupper(str[i])) //判断当前字符是否为大写字母
{
index=str[i]-'A';
while(p->next[index]==NULL&&p!=root)
p=p->fail;
p=p->next[index];
if(p==NULL) p=root;
node *temp=p;
while(temp!=root&&temp->code)
{
virus[temp->code].num+=temp->terminal;
temp=temp->fail;
}
}
else p=root; //如果不是大写字母,则指向树根
i++;
}
}
int main()
{
int n;
while(scanf("%d",&n)!=-1)
{
node *root=new node();
for(int i=1;i<=n;i++)
{
scanf("%s",virus[i].name);
virus[i].num=0;
insert(root,virus[i].name,i);
}
build_fail(root);
scanf("%s",web);
query(root,web);
for(int i=1;i<=n;i++)
if(virus[i].num) //输出出现过的病毒特征码
printf("%s: %d\n",virus[i].name,virus[i].num);
}
return 0;
}