题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896
题目大意:给定n个病毒代码和m个网站源码,问每个网站源码包含哪些病毒。
解题思路:用n个病毒代码构造一棵trie树,再增加fail指针。最后只要进行查询就可以了,差不多就是模板题。最后将求得的病毒序号排序输出即可。
测试数据:
3
aaabbb
ccc
3
aaabcccbb
aaabbbccc
bbaacc
代码:
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
struct node {
int flag,rec;
node *next[100],*fail;
node () {
flag = rec = 0;
memset(next,NULL,sizeof(next));
fail = NULL;
}
}*q[1000010];
int n,m,cnt,tot,cas;
int head,tail,arr[501];
char key[201],str[100010];
void Insert(node *root,char *str,int loc) {
int i = 0,k;
node *p = root;
while (str[i]) {
k = str[i++] - 31;
if (p->next[k] == NULL)
p->next[k] = new node();
p = p->next[k];
}
p->flag = 1;
p->rec = loc;
}
void my_accept(node *root) {
//构造失败指针
root->fail = NULL;
q[head++] = root;
while (head != tail) {
node *temp = q[tail++]; //获取头结点
node *p = NULL;
for (int i = 0; i < 100; ++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;
}//else
q[head++] = temp->next[i];
}//if ( != NULL
}//for i
}//while head != tail
}
void Search(node *root,char *str) {
int i = 0,k;
node *p = root,*temp;
while (str[i]) {
k = str[i++] - 31;
while (p->next[k] == NULL && p != root)
p = p->fail; //往前回溯求最长后缀
p = (p->next[k] ? p->next[k] : root);
temp = p;
while (temp != root) {
if (temp->flag == 1)
arr[cnt++] = temp->rec;
temp = temp->fail;
}
}
}
int main()
{
int i,j,k;
while (scanf("%d",&n) != EOF) {
node *root = new node();
for (i = 1; i <= n; ++i)
scanf("%s",key),Insert(root,key,i);
tot = head = tail = 0;
my_accept(root);
scanf("%d",&m);
for (i = 1; i <= m; ++i) {
scanf("%s",str);
cnt = 0;
Search(root,str);
if (cnt == 0) continue;
tot++;
printf("web %d:",i);
sort(arr,arr+cnt);
for (j = 0; j < cnt; ++j)
printf(" %d",arr[j]);
printf("\n");
}
printf("total: %d\n",tot);
}
}
本文ZeroClock原创,但可以转载,因为我们是兄弟。