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 }

你可能感兴趣的:(AC自动机)