刚刚看完AC自动两天就发现了这道自动机的题目,这题不是很难,但是有几个细节需要注意一下,首先网站中的病毒类型不能重复,也就是说没有可能出现两个同样的病毒,我的处理方法是利用set这样的话判重和排序都省了,其次输出的网站编号和最终的病毒网站数不是一样的(我就是卡在这里一直WA),爆栈的童鞋记得size是128,因为是全部可见字符,然后base是31也是同样的道理,这样就应该不会RE了。
#include <iostream>
#include <set>
using namespace std;
const int size = 128;
struct node
{
int count;
int id;
node *son[size];
node *fail;
node()
{
id = count = 0;
fail = NULL;
for (int i = 0; i < size; i ++){
son[i] = NULL;
}
}
}*q[100005];
int num;
void insert(char *a, node *root)
{
int len =strlen(a);
node *p = root;
for (int i = 0; i < len; i ++){
int k = a[i] - 31;
if (p -> son[k] == NULL){
p -> son[k] = new node;
}
p = p -> son[k];
}
p -> id = ++ num;
p -> count ++;
}
void build_ac_automation(node *root)
{
int head = 0, tail = 0;
root->fail = NULL;
q[tail ++] = root;
while (head != tail){
node *temp = q[head ++];
node *p = NULL;
for (int i = 0; i < 128; i ++){
if (temp -> son[i] != NULL){
if (temp == root){
temp -> son[i] -> fail = root;
}
else {
p = temp -> fail;
while (p != NULL){
if (p -> son[i] != NULL){
temp -> son[i] -> fail = p -> son[i];
break;
}
p = p -> fail;
}
if (p == NULL)temp -> son[i] -> fail = root;
}
q[tail ++] = temp -> son[i];
}
}
}
}
set<int> S;
int find(node *root, char *a)
{
S.clear();
int ans = 0, len = strlen(a);
node *p = root;
for (int i = 0; i < len; i ++){
int k = a[i] - 31;
while (p -> son[k] == NULL && p != root)p = p -> fail;
p = p -> son[k];
p = (p == NULL)? root : p;
node *temp = p;
while (temp != root ){
ans += temp -> count;
if (temp -> count)
S.insert(temp -> id);
temp = temp -> fail;
}
}
return ans;
}
char word[210], word1[10100];
int main()
{
int t, n;
scanf("%d", &n);
node *root;
num = 0;
root = new node;
while (n --){
scanf("%s", word);
insert(word, root);
}
build_ac_automation(root);
scanf("%d", &t);
int nc = 0;
int an = 0;
while (t --){
scanf("%s", word1);
++ nc;
if (find(root, word1)){
an ++;
printf("web %d: ", nc);//这里和下面的an让我WA了N次
set <int> ::iterator temp;
for (temp = S.begin(); temp != S.end(); temp++){
if (temp != S.begin())printf(" ");
printf("%d", *temp);
}
printf("\n");
}
}
printf("total: %d\n", an);
return 0;
}