hdu 1277 AC自动机入门
Posted 6262369sss
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 1277 AC自动机入门相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1277
推荐一篇博客(看思路就可以,实现用的是java):
https://www.cnblogs.com/nullzx/p/7499397.html
这是一道模板题,拿来练手,之前看了一篇博客,有点错误,但是hdu上面居然过了,最主要的是我在hdu上面三道AC自动机模板题都是这个错的代码,居然都过了,害的我纠结了一晚上,原来是数据太水了。
主要还是看上面的博客,写了点注释,不一定对,以后好拿来复习。
代码(指针写的):
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 10005 char str[maxn][62]; char s[62]; struct node{ int id;//记录当前关键字的编号 node *next[10];//指向儿子 node *fail;//失配后指向的地方,相当于KMP里面的next数组的作用 node(){ id=-1; memset(next,0,sizeof(next)); fail=NULL; } }; queue<int>qe;//记录出现的关键字编号 queue<node*>q;//BFS int n,m,k,t; void insert(char *s,node *root,int ID){//插入关键字到trie里面 node *p=root; int len=strlen(s); for(int i=0;i<len;i++){ int id=s[i]-‘0‘; if(p->next[id]==NULL) p->next[id]=new node(); p=p->next[id]; } p->id=ID;//在关键字结束的地方把id更新为关键字的ID } void build_fail(node *root){//构建fail指针,要和KMP算法联想起来作比较 while(!q.empty()) q.pop(); q.push(root); while(!q.empty()){ node *temp=q.front(); q.pop(); for(int i=0;i<10;i++){ if(temp->next[i]==NULL) continue; if(temp==root)//让root节点的所有儿子的fail指针都指向root,相当于next[0]=-1 temp->next[i]->fail=root; else{ node *p=temp->fail;//把temp->fail赋给p,因为接下来p要改变 while(p!=NULL){//一直向fail方向走,直到找到某个点的next[i]!=NULL或者p==NULL(找不到) if(p->next[i]!=NULL){ temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL)//如果找不到,就让temp的儿子i的fail指针指向根 temp->next[i]->fail=root; } q.push(temp->next[i]); } } } void query(node *root){ while(!qe.empty()) qe.pop(); node *temp=root; for(int i=0;i<n;i++){ for(int j=0;j<60;j++){ int id=str[i][j]-‘0‘; //一直往fail指向的方向找,直到找到或者到了root,相当于KMP里面K一直等于next[K],最后匹配成功或者K=-1 while(temp->next[id]==NULL&&temp!=root) temp=temp->fail; temp=temp->next[id];//temp下移 if(temp==NULL) temp=root; node *p=temp; while(p!=root){//在所有的以i+‘0‘字符结尾的前缀里面找以这个字符结束的单词 if(p->id!=-1){//注意这个p->id的位置,刚刚学,看了错的博客,把它写在了上面,hdu居然过了,纠结了我老半天 qe.push(p->id); p->id=-1;//因为可能会有多个后缀和某一个前缀相同,可能会重复计数,所以我们要标记一下 } p=p->fail; } } } } void destroy(node *root){ if(root==NULL) return; for(int i=0;i<10;i++){ if(root->next[i]!=NULL) destroy(root->next[i]); } delete root; } int main() { while(scanf("%d%d",&n,&m)!=EOF){ node *root=new node(); for(int i=0;i<n;i++) scanf("%s",str[i]); getchar(); char c; for(int i=0;i<m;i++){ int num=0;//计算空格数量,一旦达到了三个就说明接下来开始输入关键字了 while(num!=3&&(c=getchar())){ if(c==‘ ‘) num++; } scanf("%s",s);//输入关键字 insert(s,root,i);//把关键字插入字典树 } build_fail(root);//构建fail指针 query(root);//扫描 if(qe.size()==0) printf("No key can be found ! "); else{ printf("Found key:"); while(!qe.empty()){ printf(" [Key No. %d]",qe.front()+1); qe.pop(); } printf(" "); } destroy(root);//释放内存 } return 0; }
以上是关于hdu 1277 AC自动机入门的主要内容,如果未能解决你的问题,请参考以下文章
HDU4057 Rescue the Rabbit(AC自动机+状压DP)
HDU 2222 Keywords Search(AC自动机入门)