【题目大意】给出多组数据(第一行输入的N),每组数据第一行给出要录入的单词数,最后一行给出文章,要求计算录入的单词在文章中出现了多少次。
【分析】很裸的AC自动机。首先建一棵Trie树,再用类似于KMP的next数组一样对每一个Trie树结点求出对应的失败指针,从而在每次失败后,在每个录入单词中找一个最优的串的合适的位置继续进行匹配,最后对文章进行匹配即可。
→为方便查阅,给出链接:
Trie树百度百科:http://baike.baidu.com/view/1436495.htm
KMP详解:http://blog.csdn.net/u011400953/article/details/9324095
【原题地址】http://acm.hdu.edu.cn/showproblem.php?pid=2222
【代码】
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<algorithm> #include<queue> using namespace std; #define MAX 500001 struct TREE{int fail,son[26+6],num;}; TREE trie[MAX]; int CASE,N,node_num=0; int ans=0; char NOW1[101],NOW2[1000001]; void tree_clear() { ans=0; node_num=0; for(int i=0;i<=N;i++) { trie[i].fail=0; trie[i].num=0; for(int j=0;j<=26;j++) trie[i].son[j]=0; } } void insect(char *NOW) { int now=0,len=strlen(NOW); for(int i=0;i<len;i++) { if(!trie[now].son[(int)NOW[i]-(int)'a']) trie[now].son[(int)NOW[i]-(int)'a']=++node_num; now=trie[now].son[(int)NOW[i]-(int)'a']; } trie[now].num++;//=1 ? } void build_fail() { queue<int> q; int now=0; for(int i=0;i<26;i++) if(trie[now].son[i]) { q.push(trie[now].son[i]); trie[trie[now].son[i]].fail=0; } while(!q.empty()) { int point,now_fail; now=q.front(); q.pop(); for(int i=0;i<26;i++) if(point=trie[now].son[i]) { now_fail=trie[now].fail; while(now_fail && !trie[now_fail].son[i]) now_fail=trie[now_fail].fail; trie[point].fail=trie[now_fail].son[i]; q.push(point); } } } void find(char *NOW) { int len=strlen(NOW),now=0,use=0; for(int i=0;i<len;i++) { while(now && !trie[now].son[(int)NOW[i]-(int)'a']) now=trie[now].fail; now=trie[now].son[(int)NOW[i]-(int)'a']; use=now; while(use) { ans+=trie[use].num; trie[use].num=0; use=trie[use].fail; } } } int main() { //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); scanf("%d",&CASE); for(int i=1;i<=CASE;i++) { scanf("%d",&N); tree_clear(); for(int j=1;j<=N;j++) { scanf("%s",NOW1); insect(NOW1); } build_fail(); scanf("%s",NOW2); find(NOW2); printf("%d\n",ans); } return 0; }
转载注明出处:http://blog.csdn.net/u011400953