HDU 2222 Keywords Search(AC自动机)
AC自动机,这个名字有没点虎。乍一看有没有自动AC题目的意思,就是万精油模板,其实是一个匹配算法。一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。
#include<stdio.h> #include<string.h> #define MAXD 500010 #define MAXT 1000010 char b[60], txt[MAXT]; int N, next[MAXD][26], flag[MAXD], P[MAXD], q[MAXD], e, cnt; void insert(int cur, int k) { ++ e; flag[e] = 0; memset(next[e], 0, sizeof(next[e])); next[cur][k] = e; } void update() { int i, j, u, x, front, rear; front = rear = 0; P[0] = q[rear ++] = 0; while(front < rear) { u = q[front ++]; for(i = 0; i < 26; i ++) if(next[u][i]) { x = next[u][i]; if(u == 0) P[x] = 0; else { for(j = P[u]; j != 0; j = P[j]) if(next[j][i]) { P[x] = next[j][i]; break; } if(j == 0) P[x] = next[0][i]; } q[rear ++] = next[u][i]; } } } int main() { int t; scanf("%d", &t); while(t --) { int i, j, k, cur; scanf("%d", &N); e = 0; memset(next[e], 0, sizeof(next[e])); for(i = 0; i < N; i ++) { scanf("%s", b); cur = 0; for(j = 0; b[j]; j ++) { k = b[j] - 'a'; if(!next[cur][k]) insert(cur, k); cur = next[cur][k]; } ++ flag[cur]; } int t; update(); scanf("%s", txt); j = cnt = 0; for(i = 0; txt[i]; i ++) { k = txt[i] - 'a'; while(j > 0 && !next[j][k]) j = P[j]; j = next[j][k]; for(t = j; t > 0; t = P[t]) { if(flag[t] >= 0) { cnt += flag[t]; flag[t] = -1; } else break; } } printf("%d\n", cnt); } return 0; }
全名:Aho-Corasick automation。要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。难度很大,KMP和Trie都是我不怎么熟悉的地域,某一论文(全英文)很好的阐述了这个算法,不过就是英文难看了,我也没去看,就着网上其他人的文章看了看。
顺便给个地址:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
感觉这位同学写的不错了。
这题是入门的一个模板题,需要注意的是单词列表中可能有重复的单词,但这些重复的单词应看做不同的,因此建字典树时做标记的时候,把原来的赋值为1的操作变为自加1的操作。