HDU - 2222 Keywords Search (AC自动机)
2014-08-08 22:13
381 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=2222
题意:
给出n个单词,最后给出一字符串,需要找出该字符串里面出现了多少个给出的单词
每个单词出现只记录一次,例:给出单词:ab,abc。字符串为:ababab。 答案为: 1
给出的单词可以相同,例:给出单词:ab,ab,ab。字符串为:ab。答案为:3
分析:
典型的ac自动机问题
再Trie树的基础上,加一个失败指针(fail指针)即可,它指向是,若当前匹配失败后,节点跳转的位置。初始为根节点root
例如:
目前Trie树里面已有单词:abb,bc, 当前字符串为:abc。
开始从第一个单词匹配下去,当匹配到root->a->b->b,匹配失败,
然后从上一个匹配成功的地方root->a->b中的b节点开始跳转,跳转的目标是第二个单词root->b->c中的b节点
接着向下匹配,root->b->c成功,答案为1
所以,可以看出Trie树种的两条路径root->a->b->c, 和root->b->c,
第一条路径中的b节点的fail指针指向第二条路径的b节点
第二路径的b节点fail指针指向root指针...
一般的,当前路径节点上的失败指针fail,所指向的路径向上看,是当前路径的后缀,例如b 是ab后缀,所以建立Fail可以用BFS
代码:
题意:
给出n个单词,最后给出一字符串,需要找出该字符串里面出现了多少个给出的单词
每个单词出现只记录一次,例:给出单词:ab,abc。字符串为:ababab。 答案为: 1
给出的单词可以相同,例:给出单词:ab,ab,ab。字符串为:ab。答案为:3
分析:
典型的ac自动机问题
再Trie树的基础上,加一个失败指针(fail指针)即可,它指向是,若当前匹配失败后,节点跳转的位置。初始为根节点root
例如:
目前Trie树里面已有单词:abb,bc, 当前字符串为:abc。
开始从第一个单词匹配下去,当匹配到root->a->b->b,匹配失败,
然后从上一个匹配成功的地方root->a->b中的b节点开始跳转,跳转的目标是第二个单词root->b->c中的b节点
接着向下匹配,root->b->c成功,答案为1
所以,可以看出Trie树种的两条路径root->a->b->c, 和root->b->c,
第一条路径中的b节点的fail指针指向第二条路径的b节点
第二路径的b节点fail指针指向root指针...
一般的,当前路径节点上的失败指针fail,所指向的路径向上看,是当前路径的后缀,例如b 是ab后缀,所以建立Fail可以用BFS
代码:
#include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <math.h> #include <algorithm> #include <queue> #include <stack> #include <vector> #include <map> using namespace std; #define MAX 1000000+10 #define MIN -1e5 #define INF 0x7f7f7f7f int t, n, m; char str[MAX]; struct Trie { int id; // 单词出现次数 Trie *child[26]; // 连接下一个字母节点指针 Trie *fail; // 匹配失败的指针 }root, trie[MAX]; // 根节点, 静态分配节点的数组 int t_num; // 静态数组下标 void insert(char str[]) // 插入单词, 构建Trie树 { Trie *x = &root; for(int i = 0; str[i]; i++) { if(!x->child[str[i]-'a']) // 出现新节点, 初始化 { trie[t_num].id = 0; trie[t_num].fail = &root; memset(trie[t_num].child, 0, sizeof(trie[t_num].child)); x->child[str[i]-'a'] = &trie[t_num++]; } x = x->child[str[i]-'a']; // 指向下一个字母 } x->id++; // 完整的一个单词 +1 } void setFail(Trie *x, int p) // 设置单个节点(x->child[p])的失败指针fail { // 当前节点(x->child[p])的fail指针,从双亲(x)的fail指针向下查找 Trie *y = x->fail; // 一直找到所有双亲的fail查找出,子节点含有p的节点, 或者到达根节点--root while(y != &root && !y->child[p]) { y = y->fail; } // 当前双亲的fail中,子节点含有所求字母 并且 当前节点不是原节点, 则设置fail成功 if(y->child[p] && y->child[p] != x->child[p]) { x->child[p]->fail = y->child[p]; } } void buildFail() // 建立整棵树的fail指针,BFS { Trie *x = &root; // 因为当前单词的fail指针指向的新单词,为当前单词的后缀,所以新单词长度一定小于当前单词 // 因此,建立的顺序,从短到长,运用BFS进行宽度方式,逐个设置fail queue<Trie*> q; q.push(x); while(!q.empty()) { x = q.front(); q.pop(); for(int i = 0; i<26; i++) // Trie树每一层节点都遍历一遍 { if(x->child[i]) // 存在节点的, 逐个设置它们的fail指针 { setFail(x, i); q.push(x->child[i]); } } } } void query() // 查找字符串str中,出现的单词数(每个单词只计算一次) { Trie *x = &root; int ans = 0; for(int i =0; str[i]; i++) { while(x != &root && !x->child[str[i]-'a']) { x = x->fail; } if(!x->child[str[i]-'a']) continue; // 不存在当前节点, 跳过 x = x->child[str[i]-'a']; // 存在,则指向新节点,并计算 Trie *y = x; // 把存在的当前字母的所有节点,通过fail查找一遍 // 查找过的标为-1,不再查找(不是完整单词的id为0,不影响结果) while(y != &root && y->id != -1) { ans += y->id; y->id = -1; y = y->fail; } } printf("%d\n", ans); } int main() { int i, j; freopen("a.txt", "r", stdin); scanf("%d", &t); while(t--) { t_num = 0; root.fail = &root; memset(root.child, 0, sizeof(root.child)); scanf("%d", &n); char word[50+10]; for(i = 0; i<n; i++) { scanf("%s", word); insert(word); } buildFail(); scanf("%s", str); query(); } return 0; }
相关文章推荐
- hdu 2222 Keywords Search (AC自动机~)
- HDU 2222 Keywords Search (AC自动机模板题)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机模版题)
- HDU 2222 Keywords Search (ac自动机)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC 自动机入门)
- hdu 2222 Keywords Search (AC自动机)
- hdu 2222(Keywords Search) (AC自动机)
- hdu 2222 Keywords Search ( AC 自动机)
- HDU 2222——Keywords Search(AC自动机)
- HDU - 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机入门题目)
- HDU 2222 Keywords Search (AC自动机)
- HDU 2222 Keywords Search (AC自动机模板题)
- HDU 2222 Keywords Search(AC自动机)
- HDU 2222 Keywords Search (AC自动机入门 模板)
- hdu 2222 Keywords Search (ac自动机)