HDU 2896 病毒侵袭【AC自动机】
http://acm.hdu.edu.cn/showproblem.php?pid=2896
HDU 2896 病毒侵袭
大意:
有n种病毒,编码已知。有m个网站源码,求带病毒的网站个数以及其对应的病毒
Sample Input
3
aaa
bbb
ccc
2
aaabbbccc
bbaacc
Sample Output
web 1: 1 2 3
total: 1
hint:有3种病毒,编码分别为
aaa
bbb
ccc
2个网站,其中网站1包含了编号1,2,3病毒关键字
分析:
AC自动机。
PS:学长出的题,算是模板题吧。。。。贴上来,备着O(∩_∩)O~
View Code
1 #include<iostream>
2 #include<queue>
3 using namespace std;
4
5 //子树节点是在插入时new的,
6 //寻找失配指针中使用的队列是直接调用STL的
7 const int kind = 100;//子树个数,因可见ASCII码为32-126,少于100个
8 bool visited[500+10];//记录当前病毒是否被访问
9 int ansid[4];
10 int ansnum;
11 struct node
12 {
13 node *fail;
14 node *next[kind];
15 int count;//记录当前前缀是完整单词出现的个数
16 int id;//记录病毒编号
17 node()
18 {
19 fail = NULL;
20 count = 0;
21 memset(next,NULL,sizeof(next));
22 }
23 };//寻找失配指针时需要用到的队列
24
25 char keyword[201+10];//关键字
26 char str[80000];//主串
27 void insert(char *str,node *root,int id)
28 {
29 node *p=root;
30 int i=0,index;
31 while(str[i])
32 {
33 index = str[i]-31;
34 if(p->next[index]==NULL)
35 p->next[index]=new node();
36
37 p=p->next[index];
38 i++;
39 }
40 p->count++;
41 p->id = id;
42 }
43
44 //寻找失败指针
45 void build_ac_automation(node *root)
46 {
47 int i;
48 queue<node *>Q;
49 root->fail = NULL;
50 Q.push(root);
51 while(!Q.empty())
52 {
53 node *temp = Q.front();//q[head++];//取队首元素
54 Q.pop();
55 node *p = NULL;
56 for(i=0;i<kind;i++)
57 {
58 if(temp->next[i]!=NULL)//寻找当前子树的失败指针
59 {
60 p = temp->fail;
61 while(p!=NULL)
62 {
63 if(p->next[i]!=NULL)//找到失败指针
64 {
65 temp->next[i]->fail = p->next[i];
66 break;
67 }
68 p = p->fail;
69 }
70
71 if(p==NULL)//无法获取,当前子树的失败指针为根
72 temp->next[i]->fail = root;
73
74 Q.push(temp->next[i]);
75 }
76 }
77 }
78 }
79
80 //询问str中包含n个关键字中多少种
81 void query(node *root)
82 {
83 int i = 0,cnt = 0,index,len;
84 ansnum = 0;
85 memset(visited,false,sizeof(visited));
86 len = strlen(str);
87 node *p = root;
88 while(str[i])
89 {
90 index = str[i]-31;
91 while(p->next[index]==NULL&&p!=root)//失配
92 p=p->fail;
93 p=p->next[index];
94 if(p==NULL)//失配指针为根
95 p = root;
96
97 node *temp = p;
98 while(temp!=root)//寻找到当前位置为止是否出现病毒关键字
99 {
100 if(temp->count!=0&&visited[temp->id]==false)
101 {
102 visited[temp->id]=true;
103 ansid[ansnum++]=temp->id;
104 if(ansnum==3)return;
105 }
106
107 temp=temp->fail;
108 }
109 i++;
110 }
111 }
112 int main()
113 {
114 int n,t;
115 while(scanf("%d",&n)!=EOF)
116 {
117
118 node *root = new node();
119 getchar();
120 int id = 0;
121 while(n--)
122 {
123
124 gets(keyword);
125 insert(keyword,root,++id);
126 }
127
128 //求失败指针
129 build_ac_automation(root);
130 int m;
131 scanf("%d",&m);
132 id=0;
133 int total = 0;
134 while(m--)
135 {
136 scanf("%s",str);
137 query(root);
138 id++;
139 if(ansnum!=0)
140 {
141 total++;
142 printf("web %d:",id);
143 sort(ansid,ansid+ansnum);//不要忘记排序,错在这里就郁闷了o(>﹏<)o
144 for(int i=0;i<ansnum;i++)
145 printf(" %d",ansid[i]);
146 printf("\n");
147 }
148 }
149 printf("total: %d\n",total);
150 }
151 return 0;
152 }
2 #include<queue>
3 using namespace std;
4
5 //子树节点是在插入时new的,
6 //寻找失配指针中使用的队列是直接调用STL的
7 const int kind = 100;//子树个数,因可见ASCII码为32-126,少于100个
8 bool visited[500+10];//记录当前病毒是否被访问
9 int ansid[4];
10 int ansnum;
11 struct node
12 {
13 node *fail;
14 node *next[kind];
15 int count;//记录当前前缀是完整单词出现的个数
16 int id;//记录病毒编号
17 node()
18 {
19 fail = NULL;
20 count = 0;
21 memset(next,NULL,sizeof(next));
22 }
23 };//寻找失配指针时需要用到的队列
24
25 char keyword[201+10];//关键字
26 char str[80000];//主串
27 void insert(char *str,node *root,int id)
28 {
29 node *p=root;
30 int i=0,index;
31 while(str[i])
32 {
33 index = str[i]-31;
34 if(p->next[index]==NULL)
35 p->next[index]=new node();
36
37 p=p->next[index];
38 i++;
39 }
40 p->count++;
41 p->id = id;
42 }
43
44 //寻找失败指针
45 void build_ac_automation(node *root)
46 {
47 int i;
48 queue<node *>Q;
49 root->fail = NULL;
50 Q.push(root);
51 while(!Q.empty())
52 {
53 node *temp = Q.front();//q[head++];//取队首元素
54 Q.pop();
55 node *p = NULL;
56 for(i=0;i<kind;i++)
57 {
58 if(temp->next[i]!=NULL)//寻找当前子树的失败指针
59 {
60 p = temp->fail;
61 while(p!=NULL)
62 {
63 if(p->next[i]!=NULL)//找到失败指针
64 {
65 temp->next[i]->fail = p->next[i];
66 break;
67 }
68 p = p->fail;
69 }
70
71 if(p==NULL)//无法获取,当前子树的失败指针为根
72 temp->next[i]->fail = root;
73
74 Q.push(temp->next[i]);
75 }
76 }
77 }
78 }
79
80 //询问str中包含n个关键字中多少种
81 void query(node *root)
82 {
83 int i = 0,cnt = 0,index,len;
84 ansnum = 0;
85 memset(visited,false,sizeof(visited));
86 len = strlen(str);
87 node *p = root;
88 while(str[i])
89 {
90 index = str[i]-31;
91 while(p->next[index]==NULL&&p!=root)//失配
92 p=p->fail;
93 p=p->next[index];
94 if(p==NULL)//失配指针为根
95 p = root;
96
97 node *temp = p;
98 while(temp!=root)//寻找到当前位置为止是否出现病毒关键字
99 {
100 if(temp->count!=0&&visited[temp->id]==false)
101 {
102 visited[temp->id]=true;
103 ansid[ansnum++]=temp->id;
104 if(ansnum==3)return;
105 }
106
107 temp=temp->fail;
108 }
109 i++;
110 }
111 }
112 int main()
113 {
114 int n,t;
115 while(scanf("%d",&n)!=EOF)
116 {
117
118 node *root = new node();
119 getchar();
120 int id = 0;
121 while(n--)
122 {
123
124 gets(keyword);
125 insert(keyword,root,++id);
126 }
127
128 //求失败指针
129 build_ac_automation(root);
130 int m;
131 scanf("%d",&m);
132 id=0;
133 int total = 0;
134 while(m--)
135 {
136 scanf("%s",str);
137 query(root);
138 id++;
139 if(ansnum!=0)
140 {
141 total++;
142 printf("web %d:",id);
143 sort(ansid,ansid+ansnum);//不要忘记排序,错在这里就郁闷了o(>﹏<)o
144 for(int i=0;i<ansnum;i++)
145 printf(" %d",ansid[i]);
146 printf("\n");
147 }
148 }
149 printf("total: %d\n",total);
150 }
151 return 0;
152 }