每次第一道模板题都是非常有意义的,考试前夕费尽心思学了KMP,学了Trie树,就是为了学这个做铺垫的,这道题时著名的AC自动机模板题。个人理解AC自动机就是在一棵Trie树上求失配指针,然后实现了多模匹配。只需遍历一次文本串就能求出所有的内容。在下面的query代码里,因为不能重复计算相同的模板串,所以每次加上后temp->count=-1,表示已经算过,在while循环里temp->count!=-1的时候才进行失配其实是有意义的,当temp->count==-1时说明已经沿着失配指针匹配过一次了,所以就没有必要再往上跑一次。假如每次匹配完我令temp->count=0,然后while循环里少了temp->count!=-1的话也是可以过的,前者200ms,后者600ms,就是因为多了不必要的计算。下面贴一记代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 |
// // main.cpp // AC auto machine // // Created by change on 14-1-24. // Copyright (c) 2014年 chanme. All rights reserved. // #include <iostream> #include <cstring> #include <queue> #include <cstdio> #include <algorithm> #define MAXCHAR 26 #define maxn 500000 using
namespace
std; struct
TrieNode { int
count; TrieNode* next[MAXCHAR]; TrieNode* fail; void
init() { memset (next,0, sizeof (next)); fail=NULL; count=0; } }T[maxn],*Trie; int
top; void
insert( char
*c) { int
len=( int ) strlen (c);TrieNode *p=Trie; for ( int
i=0;i<len;i++){ if (p->next[c[i]- ‘a‘ ]!=NULL){ p=p->next[c[i]- ‘a‘ ]; } else { T[top].init(); p->next[c[i]- ‘a‘ ]=&T[top++]; p=p->next[c[i]- ‘a‘ ]; } } p->count++; } void
getFail() { queue<TrieNode *> que; // 用于BFS的队列 que.push(Trie); // 将根结点压入 Trie->fail=NULL; // 根结点的失配指针为NULL while (!que.empty()) { TrieNode* temp=que.front(); que.pop(); TrieNode* p=NULL; // 枚举每个后继 for ( int
i=0;i<MAXCHAR;i++){ // 后继非空时计算其失配指针 if (temp->next[i]!=NULL) { // 根结点的所有后继的失配指针指向根结点 if (temp==Trie){ temp->next[i]->fail=Trie; } 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=Trie; } // 压入队列 que.push(temp->next[i]); } } } } int
query( char
*c) { int
len=( int ) strlen (c); int
res=0; TrieNode *p=Trie; for ( int
i=0;i<len;i++){ while (p->next[c[i]- ‘a‘ ]==NULL && p!=Trie) p=p->fail; p=p->next[c[i]- ‘a‘ ]; if (p==NULL) p=Trie; TrieNode *temp=p; while (temp!=Trie&&temp->count!=-1){ res+=temp->count; temp->count=-1; temp=temp->fail; } } return
res; } char
str[55]; char
text[1005000]; int
n; int
main() { int
cas;cin>>cas; while (cas--) { top=0;T[top].init(); Trie=&T[top++]; cin>>n; for ( int
i=0;i<n;i++){ scanf ( "%s" ,str); insert(str); } getFail(); scanf ( "%s" ,text); printf ( "%d\n" ,query(text)); } return
0; } |
原文:http://www.cnblogs.com/chanme/p/3532917.html