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
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果七plus流量打不开怎么办 苹果手机突然打不开流量怎么办 天猫商家迟迟不发货怎么办 苹果7开不开机了怎么办 苹果机黑屏了开不起来怎么办 美团收银机连不上网怎么办 6s换电池后黑屏怎么办 苹果上的软件打不开也删不掉怎么办 苹果手机打开软件打不开怎么办 苹果电脑下载的软件打不开怎么办 苹果手机下载的软件都打不开怎么办 苹7果屏幕黑屏怎么办 苹果6s手机打不开怎么办 苹果ipad密码输入打不开怎么办 苹果平板黑屏了打不开怎么办 苹果6sp电影商城打不开怎么办 苹果6应用商城打不开怎么办 游戏下载好了安装不上怎么办 苹果5s应用商店不见了怎么办 id被停用手机白板打不开怎么办 苹果6s下载不了软件怎么办 苹果下载的软件打不开怎么办 苹果6s下不了app怎么办 苹果手机因为闪退打不开了怎么办 天猫方糖坏了怎么办 天猫魔盒的遥控器坏了怎么办 天猫盒子没声音怎么办 天猫魔盒播放声音很低怎么办 天猫魔盒3a卡顿怎么办 天猫网络机顶盒打不开了怎么办 天猫机顶盒遥控器丢了怎么办 天猫机顶盒没有遥控器怎么办 天猫机顶盒很卡怎么办 天猫机顶盒没遥控器怎么办 天猫机顶盒看不了怎么办 天猫机顶盒变黑白怎么办 天猫精灵丢了怎么办 咪咕盒子没信号怎么办 猫los灯亮了怎么办 网络猫los闪红灯怎么办 台式电脑二级网页打不开.怎么办