ac 自动机
来源:互联网 发布:平板上的淘宝怎么开店 编辑:程序博客网 时间:2024/06/11 01:57
/*以hdu 3065为例ac自动机=kmp+trie与kmp的思想是一样的,不过实现起来就有相当多的细节问题了。1.建立字典树是必须的,ch[i][j],i是节点编号,j是儿子。每一个节点都隐含有MAX_SIZE个儿子的指针,0表示该儿子不存在,其他值表示她的位置2.算出失配边,对于ch[i][j]!=0的处理方法与kmp中是相同的。但对于ch[i][j]=0的处理有两种,①不处理,直接跳过,continue②把ch[i][j],赋值为 ch[Fail[i]][j],这样做的原因是简化代码,提高程序效率。分析:在kmp中,有这么一句话while(j>=0&&T[i]!=S[j+1])j=Fail[j];即: 当扫到目标串的i位时,不匹配则沿着失配边一直走下去。同样 ac自动机中也是这样:当扫到目标串的i位时,不匹配则沿着失配边一直走下去。②的处理先一步走完了相连的第一个失配边。失配边是按节点的深度递推下来的,而失配边边必然连向了一个深度较小的节点,较小的点的失配边已经处理,这样ch[i][j]直接变成了第一个能够与T正在处理的那一位匹配的节点的编号或0(根节点)。当开始与T匹配时,就不再需要沿失配边走的语句了,直接j=ch[j][i],i是T的那一位的值(说的模糊,看代码就知道了)3.开始与T匹配了,处理与kmp几乎完全相同,就是2.②的变化。。对于不同的题处理也就不同了,当有多个目标串T对Ac_Trie操作时,一定要保证Ac_Trie不变!!*/#include<cstdio>#include<cstring>#include<iostream>#include<queue>#include<string>#include<algorithm>using namespace std;int const MAX_NODE=1010*55;int const MAX_SIZE=128;char mp[1010][55];int ans[1010];struct Ac_Trie{ int ch[MAX_NODE][MAX_SIZE],Fail[MAX_NODE],value[MAX_NODE];/*ch[][]用来建字典树,Fail[]表示失配边,value[]存储的是字典树中该节点存储的信息value[i]=-1,表示从root到编号为i的节点所形成的字符串不存在ch[i][j],表示编号为i的节点的第j个儿子节点,ch[i][j]=0表示此路径不存在,否则她的值为节点i沿边j走下去的下一个节点编号其中ch[i][j]=-1,0,可赋予不同的意义,视题意而定*/ int root,tot; int newnode() { memset(ch[tot],0,sizeof(ch[tot])); value[tot++]=-1; return tot-1; } void init() { tot=0; root=newnode(); } void insert(char *s,int key)//构造trie树 { int len=strlen(s); int u=root; for(int i=0;i<len;i++) { int v=s[i]; if(!ch[u][v]) ch[u][v]=newnode(); u=ch[u][v]; } value[u]=key; } void build()//构造自动机 { queue<int>Q; Fail[root]=root; for(int i=0;i<MAX_SIZE;i++) if(ch[root][i]) { Fail[ch[root][i]]=root; Q.push(ch[root][i]); } while(!Q.empty()) { int now=Q.front();Q.pop(); for(int i=0;i<MAX_SIZE;i++) { if(ch[now][i]) { Fail[ch[now][i]]=ch[Fail[now]][i]; Q.push(ch[now][i]); } else ch[now][i]=ch[Fail[now]][i]; } } } void Ac(char *T)//与目标串匹配 { int len=strlen(T); int u=root; for(int i=0;i<len;i++) { int v=T[i]; u=ch[u][v]; int temp=u; while(temp) { if(value[temp]!=-1) ans[value[temp]]++; temp=Fail[temp]; } } }};char T[2000010];Ac_Trie Ac;int main(){ int n,m; while(scanf("%d",&n)!=EOF) { Ac.init(); for(int i=1;i<=n;i++) { scanf("%s",mp[i]); Ac.insert(mp[i],i); } Ac.build(); scanf("%s",T); memset(ans,0,sizeof(ans)); Ac.Ac(T); for(int i=1;i<=n;i++) { // cout<<ans[i]<<endl; if(ans[i]) printf("%s: %d\n",mp[i],ans[i]); } } return 0;}
0 0
- AC自动机...
- AC自动机
- AC 自动机
- AC自动机
- AC自动机
- ac自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC 自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- DRP学习总结
- jsp学习中。。发现用中文参数创建Cookie会报错,要用编码解码解决。
- 王家林最受欢迎的一站式云计算大数据和移动互联网解决方案课程 V1(20140809)之Android移动开发高手进阶必修的8堂课
- Ajax请求,Controller处理,并跳转
- ERROR:java.lang.IllegalStateException: No output folder
- ac 自动机
- Hibernate学习_004_Hibernate中常用的主键生成策略总结(下)Annotation方式
- uva 131(枚举子集)
- nyist oj 19 擅长排列的小明(dfs搜索+STL)
- Service
- ptr_fun学习笔记
- Ubuntu14.04LTS x64 Eclipse图标为问号及深度音乐卸载后声音状态栏仍显示的解决方法
- android 开发UI好工具-----dump View Hierarchy for UI automator
- HDOJ题目2122Ice_cream’s world III(最小生成树)