AC自动机模板
2015-11-10 21:53
148 查看
在串里找单词实际上是一个一个找,找到一个字符一样,加上他的count值,然后通过失败指针返回根节点,
所以要用一个temp来这样做,p的指针始终通过主串来改变,找到一个字符相等,p不变,temp变,再比较p
的儿子与主串中下一个字符,重复以上操作
所以要用一个temp来这样做,p的指针始终通过主串来改变,找到一个字符相等,p不变,temp变,再比较p
的儿子与主串中下一个字符,重复以上操作
#include<iostream> #include<queue> #include<cstring> #include<cstdio> #define maxn 1000005 using namespace std; int head,tail;//队列头尾指针 struct node { node *fail; //fail指针表指向与与该元素相同的节点或根节点 node *next[26];//26个小写字母 int count;//记录每一个单词的末尾 node() //结构体重载 { fail =NULL; memset(next,0,sizeof(next)); count = 0 ; } }*q[maxn]; node *root; void insert(char s[])//建立字典树,这里就是26叉树 { node *p=root; int len =strlen(s); for(int i=0;i<len;i++) { int id=s[i]-'a'; if(p->next[id]==NULL) p->next[id]=new node();//若根节点下当前字符没有出现过,新建里一个当前字符的节点 p=p->next[id];//p指向当前节点 } p->count++;//单词末尾的次数加1,代表右边出现过几个最后一个字符为末尾元素的子串 } void build_ac()//建立fail指针 { node *p,*temp=NULL; q[tail++]=root;//根节点先入队 while(head!=tail) //队列不为空时 { p=q[head++];//出队 for(int i=0;i<26;i++)//26叉树,寻找单词的首字母 { if(p->next[i])//不为空就表示该字符存在 { if(p==root)//当孩子的父亲为根节点,也就是该字符位于第一层 p->next[i]->fail=root; //直接将失败指针指向根节点 else { temp = p->fail;//否则先记录当前节点的失败指针 while(temp!=NULL)//当指向为空时,跳出,这里有个误区,不能在temp等于root时跳出,因为可能根节点的儿子中存在与当前节点儿子相同的字符 { if(temp->next[i]) //如果当前节点指向的失败指针的儿子与当前节点的儿子相同 { p->next[i]->fail=temp->next[i];//将当前节点的儿子的失败指针指向它 break; } temp=temp->fail;//否则一直找与当前节点相同的元素 } if(temp==NULL) p->next[i]->fail=root;//找不到,则直接把当前节点的儿子指向根节点 } q[tail++]=p->next[i];//将当前节点的儿子入队以便在下一层完成他儿子的失败指针 } } } } int query(char s[])//查找有几个单词出现 { node *p=root,*temp; int len = strlen(s); int res=0; for(int i=0;i<len;i++) { int id =s[i]-'a'; while(p->next[id]==NULL&&p!=root) p=p->fail;//如果p位于字典树一边的末尾,跳转到与p儿子相同元素的,若没有跳转到根节点 p=p->next[id];//p指向当前元素 if(p==NULL) p=root;//如果这样的字符不存在,则指向根节点 temp = p;//p不能改变,否则下一个字符就无法比较 while(temp!=root&&temp->count!=-1)//终点就是回到根而且再找的过程中找到一个必须标记为找过,否则会重复加 { res+=temp->count;//加上当前字符的count值 temp->count=-1; //标记为访问过 temp=temp->fail; //不断找同的元素。直到回到根 } } return res; }
相关文章推荐
- 关于兔子问题(斐波那契数)的Java实现--采用面向对象的方式
- 开发之正则表达式初步
- 我的iOS学习历程 - UIView和UILabel
- sql server数据库中 INFORMATION_SCHEMA的用法
- 《JAVA----day01和day02》
- kworker内核工作队列详解
- 新手学EasyUI(七)----DataGrid CheckBox 动态选中
- 压缩包密码破解
- C++基础::关于区间端点的问题
- asp.net mvc 链接到其他area地址
- Corba 学习笔记 (一)
- codeforces GYM 100792H
- 杭电1069--Monkey and Banana 子序列,dp
- 圆角图片
- Shiro使用和源码分析---5
- A. Vitaly and Night
- [问题排障] ssh登录,密码提示出现慢的解决方法
- lightoj1297(二分查找,或求导)
- react native image resizeMode理解
- gdb反向调试命令