HDU - 2222 Keywords Search (AC自动机)
来源:互联网 发布:金蝶软件kis 编辑:程序博客网 时间:2024/04/30 21:03
题目: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
代码:
#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 0x7f7f7f7fint 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的节点, 或者到达根节点--rootwhile(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进行宽度方式,逐个设置failqueue<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;}
0 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 2222Keywords Search (ac自动机)
- HDU 2222 Keywords Search(AC自动机)
- HDU-2222 Keywords Search(AC自动机)
- [LeetCode]Merge K sorted List合并K个有序链表
- 实现中等难度通讯录。需求: 1、定义联系人类AddressContact。实例变量:姓名(拼音,首字母大写)、性别、电话号码、住址、分组名称、年龄。方法:自定义初始化方法(姓名、电话号码)、显示联系人
- UVa11709 - Trust groups(Kosaraju,十字链表)
- 【BFS】uva10047The Monocycle
- python使用pygal进行绘制数据图表和监控图表
- HDU - 2222 Keywords Search (AC自动机)
- 三、进攻的敌人
- 对反射的理解
- 北京将严打电商售假:严重违法者将注销网站
- c++常用xml解析方式
- poj 2653 Pick-up sticks 计算几何
- 如何推广自己的网站,做好自己的排名?
- 我国网民过半购物抛弃实体店
- 豆瓣推出“豆瓣”应用 整合布局移动端?