HDU 2222 Keywords Search
2013-09-30 21:22
316 查看
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2222
题意:给定一个字符串和n个单词,问字符串中共出现了多少个单词。
解析:这是AC自动机最基础的题目,也是我接触的第一个AC自动机的题目。AC自动机的话,大家可以去参考一下/article/2390636.html这篇博客,我感觉讲的很详细。然后基本上大致编出来AC自动机没问题。
但是有些需要注意的地方
1.在储存节点是否为单词节点时(我是用val,上面的链接中用的是count)一定要注意出现的单词可能重复,所以必然val是++,
2.不能直接memset(ch,0,sizeof(ch)),这样的话会MLE,虽说不知道为什么╮(╯▽╰)╭
题意:给定一个字符串和n个单词,问字符串中共出现了多少个单词。
解析:这是AC自动机最基础的题目,也是我接触的第一个AC自动机的题目。AC自动机的话,大家可以去参考一下/article/2390636.html这篇博客,我感觉讲的很详细。然后基本上大致编出来AC自动机没问题。
但是有些需要注意的地方
1.在储存节点是否为单词节点时(我是用val,上面的链接中用的是count)一定要注意出现的单词可能重复,所以必然val是++,
2.不能直接memset(ch,0,sizeof(ch)),这样的话会MLE,虽说不知道为什么╮(╯▽╰)╭
#include"stdio.h" #include"string.h" #include"queue" using namespace std; #define maxnode (500005) #define sigma_size 26 struct AC_automation{ struct node{ int next[sigma_size]; int val; //树节点的附加信息 int fail; //存储节点的失配指针 void init(){ memset(next,0,sizeof(next)); fail = val = 0; } }ch[maxnode]; //用来存储Trie树 int sz; //整棵树节点的总数 int idx(char c){ return c - 'a'; //对于小写字母集,获得c的编号 } void init(){ sz = 1; ch[0].init(); // memset(ch,0,sizeof(ch)); //虽然不知道为什么,但是加上这句就MLE } void insert(char *s){ int u = 0,len = strlen(s); for(int i = 0 ; i < len ; i ++){ int c = idx(s[i]); if(ch[u].next[c] == 0){ ch[sz].init(); ch[u].next[c] = sz++; } u = ch[u].next[c]; } ch[u].val++; //此处不可以是ch[u].val = 1;因为可能有多个相同的单词 } //利用bfs得到失配指针fail void get_fail(){ queue<int>Q; for(int i = 0 ; i < sigma_size; i ++) if(ch[0].next[i] != 0) Q.push(ch[0].next[i]); while(!Q.empty()){ int temp = Q.front(); Q.pop(); for(int i = 0 ; i < sigma_size; i ++){ if(ch[temp].next[i] != 0){ Q.push(ch[temp].next[i]); int fail_temp = ch[temp].fail; //关键步骤,如果fail指针所指的节点没有('a'+i)这个子节点,继续递归,直到fail_temp指向0节点,即根节点 while(fail_temp > 0 && ch[fail_temp].next[i] == 0) fail_temp = ch[fail_temp].fail; if(ch[fail_temp].next[i] != 0) //如果fail_temp节点的子节点有('a'+i)这个字符 fail_temp = ch[fail_temp].next[i]; ch[ch[temp].next[i]].fail = fail_temp; //子节点的失配节点由父节点节点决定 } } } } //寻找text[]总共有多少个单词 int get_word_num(char *text){ int ans = 0; int len = strlen(text); int node = 0,fail_temp = 0; for(int i = 0 ; i < len ; i ++){ int character = idx(text[i]); while(fail_temp > 0 && ch[fail_temp].next[character] == 0) //若没有text[i]这个字符,则使用失配指针继续在Trie树上遍历 fail_temp = ch[fail_temp].fail; if(ch[fail_temp].next[character] != 0){ //此时找到了text[i]这个字符 fail_temp = ch[fail_temp].next[character]; int fail_temp2 = fail_temp; //此处必须有另一个变量来记录失配的时候的下标 while(fail_temp2 > 0 && ch[fail_temp2].val){ //在向上遍历失配函数的时候,只有当该节点是单词节点,才会继续失配 ans += ch[fail_temp2].val; ch[fail_temp2].val = 0; //防止重复计算,把该单词节点删去 fail_temp2 = ch[fail_temp2].fail; } } } return ans; } }AC; int N; char text[1000010]; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&N); char str_temp[55]; AC.init(); for(int i= 0 ; i < N; i ++){ scanf("%s",str_temp); AC.insert(str_temp); memset(str_temp,0,sizeof(str_temp)); } AC.get_fail(); scanf("%s",text); printf("%d\n",AC.get_word_num(text)); } return 0; }
相关文章推荐
- hdu2222 Keywords Search
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search
- 【hdu 2222】Keywords Search 中文题意&题解&代码(C++)
- HDU 2222 Keywords Search
- HDU 2222 Keywords Search (AC 自动机入门)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search
- Hdu 2222 Keywords Search
- HDU 2222 Keywords Search
- hdu 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search
- HDU 2222 Keywords Search
- HDU 2222 Keywords Search (ac自动机)
- HDU 2222 Keywords Search (AC自动机入门题目)
- AC自动机初识&hdu 2222 Keywords Search
- HDU-2222 Keywords Search
- HDU 2222 — Keywords Search
- HDU 2222 Keywords Search