1 /*
2 hdu 2896 病毒侵袭 ac自动机
3 从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉
4 last[]数组主要是记录具有相同后缀模式串的末尾节点编号 。本题中主要是计算每一个模式串
5 在主串中有没有出现过,而不是计算出现过多少次,所以将last[]数组省掉....
6 */
7 #include<algorithm>
8 #include<iostream>
9 #include<cstdio>
10 #include<cstring>
11 #include<queue>
12 #define N 210*500
13 using namespace std;
14 class AC_atomata
15 {
16 public:
17 int trie[N][128], f[N], val[N];
18 int vis[510];
19 int nodeN;
20 int total;
21 queue<int>q;
22 void init()
23 {
24 nodeN=0;
25 val[0]=0;
26 total=0;
27 while(!q.empty()) q.pop();
28 memset(trie[0], 0, sizeof(trie[0]));
29 }
30 void build(char *str, int index);//建立trie树
31 void getFail();//失配函数
32 void find(char *T, int n, int index);//查找函数
33 };
34
35
36 void AC_atomata::build(char *str, int index)
37 {
38 int i, u;
39 for(i=0, u=0; str[i]; ++i)
40 {
41 int ch=str[i];
42 if(!trie[u][ch])
43 {
44 trie[u][ch]=++nodeN;
45 memset(trie[nodeN], 0, sizeof(trie[nodeN]));
46 }
47 u=trie[u][ch];
48 val[u]=0;
49 }
50 val[u]=index;
51 }
52
53 void AC_atomata::getFail()
54 {
55 int r, u, v, i;
56 f[0]=0;
57 for(i=0; i<128; ++i)
58 {
59 if(trie[0][i])
60 {
61 q.push(trie[0][i]);
62 f[trie[0][i]]=0;
63 }
64 }
65 while(!q.empty())
66 {
67 r=q.front();
68 q.pop();
69 for(i=0; i<128; ++i)
70 {
71 u=trie[r][i];
72 if(!u) continue;
73 q.push(u);
74 v=f[r];
75 while(v && !trie[v][i]) v=trie[v][i];
76 f[u]=trie[v][i];
77 }
78 }
79 }
80
81 void AC_atomata::find(char *T, int n, int index)
82 {
83 int i, u;
84 int cnt=0, v[3];
85 memset(v, 0, sizeof(v));
86 memset(vis, 0, sizeof(vis));//每一次查找将数组初始化,开始忘记初始化了, 哇了好多次
87 for(i=0, u=0; T[i]; ++i)
88 {
89 int ch=T[i];
90 while(u && !trie[u][ch]) u=f[u];
91 u=trie[u][ch];
92 if(val[u] && !vis[val[u]])
93 {
94 v[cnt++]=val[u];
95 vis[val[u]]=1;
96 if(cnt>2) break;
97 }
98 }
99 if(cnt>0)
100 {
101 ++total;
102 printf("web %d:", index);
103 sort(v, v+3);
104 for(i=0; i<3; ++i)
105 if(v[i]) printf(" %d", v[i]);
106 printf("\n");
107 }
108 }
109
110 AC_atomata ac;
111 char T[10005], s[205];
112
113 int main()
114 {
115 int n, m, i;
116 while(scanf("%d", &n)!=EOF)
117 {
118 ac.init();
119 for(i=1; i<=n; ++i)
120 {
121 scanf("%s", s);
122 ac.build(s, i);
123 }
124 ac.getFail();
125 scanf("%d", &m);
126 for(i=1; i<=m; ++i)
127 {
128 scanf("%s", T);
129 ac.find(T, n, i);
130 }
131 printf("total: %d\n", ac.total);
132 }
133 return 0;
134 }



1 /*
2 上面的程序过了,感觉数据很水....
3 */
4 #include<iostream>
5 #include<cstdio>
6 #include<cstring>
7 #include<queue>
8 #define N 100005
9 #define M 505
10 using namespace std;
11 int n, m;
12 class AC_atomata
13 {
14 public:
15 int trie[N][128], fail[N];
16 int cnt;
17 int vis[M];//标记边
18 int nodeN;//节点数
19 int val[N];//标记字符节点是否为单词末尾
20 queue<int>q;
21 void init();
22 void build(char *T, int index) ;
23 void getFail();
24 void find(char *S, int index);
25 };
26
27 void AC_atomata:: init()
28 {
29 while(!q.empty()) q.pop();
30 memset(trie[0], 0, sizeof(trie[0]));
31 nodeN=0;
32 cnt=0;
33 memset(val, 0, sizeof(val));
34 }
35
36 void AC_atomata:: build(char *T, int index)
37 {
38 int i, u=0;
39 for(i=0; T[i]; ++i)
40 {
41 if(trie[u][T[i]]==0)
42 {
43 trie[u][T[i]]=++nodeN;
44 memset(trie[nodeN], 0, sizeof(trie[nodeN]));
45 }
46 val[u]=0;
47 u=trie[u][T[i]];
48 }
49 val[u]=index;
50 }
51
52 void AC_atomata:: getFail()
53 {
54 int r, u, v;
55 int c, root=0;
56 fail[root]=0;
57 for(c=0; c<128; ++c)
58 {
59 if(v=trie[root][c])
60 {
61 fail[v]=root;
62 q.push(v);
63 }
64 }
65 while(!q.empty())
66 {
67 r=q.front(); q.pop();
68 for(c=0; c<128; ++c)
69 {
70 u=trie[r][c];
71 if(!u)//该节点不存在,也就是查找过程中每一个节点都是平等的
72 trie[r][c]=trie[fail[r]][c];
73 else
74 {
75 fail[u]=trie[fail[r]][c];
76 q.push(u);
77 }
78 }
79 }
80 }
81
82 void AC_atomata:: find(char *S, int index)
83 {
84 int cur, root, count=0;
85 cur=root=0;
86 memset(vis, 0, sizeof(vis));
87 for(int i=0; S[i]; ++i)
88 {
89 cur=trie[cur][S[i]];
90 int next=cur;


          //这个while循环就是last[]数组实现的功能,只不过是last[]数组记录的总是单词结尾字符的节点的编号

          //而我们通过沿着 next 节点的失配方向一直搜索, 也可以寻找到 以next节点所对应字符结尾的单词

91        while(next!=root)
92 {
93 if(val[next])
94 {
95 vis[val[next]]=1;
96 count++;
97 }
98 next=fail[next];
99 }
100 }
101 if(count>0)
102 {
103 ++cnt;
104 printf("web %d:", index);
105 for(int i=1; i<=n; ++i)
106 if(vis[i])
107 printf(" %d", i);
108 printf("\n");
109 }
110 }
111
112 char t[205], s[10005];
113 AC_atomata ac;
114 int main()
115 {
116 int i;
117 while(scanf("%d", &n)!=EOF)
118 {
119 ac.init();
120 for(i=1; i<=n; ++i)
121 {
122 scanf("%s", t);
123 ac.build(t, i);
124 }
125 ac.getFail();
126 scanf("%d", &m) ;
127 for(i=1; i<=m; ++i)
128 {
129 scanf("%s", s);
130 ac.find(s, i);
131 }
132 printf("total: %d\n", ac.cnt);
133 }
134 return 0;
135 }