AC自动机精讲
2016-06-22 11:09
204 查看
http://www.cnblogs.com/Booble/archive/2010/12/05/1897121.html
//hdu2222 //ACauto //构造失败指针:设当前节点上的字母为C,沿着他父亲的失败指针走,直到走到一个节点,他的儿子中也有字母为C的。然后把当前节点的失败指针指向那个字母也为C的儿子。如果一直走到了root都没找到,那就把失败指针指向root。 //匹配(1)当前字符匹配,只需沿该路径走向下一个节点继续匹配即可;(2)当前字符不匹配,则去当前节点失败指针所指向的字符继续匹配.重复这2个过程中的一个,直到模式串走完。 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<queue> #define cha 26 #define Root 0 #define N 500001 using namespace std; struct node{ int data;//结点信息 int count;//从根到此处是否是关键字,并且记录是多少个关键字的结尾 int fail; int next[cha]; }tree ; void init(node &a,int data){ a.data = data; a.count = 0; a.fail = Root; for(int i=0;i<cha;i++) a.next[i] = -1; } int k = 1; void Insert(char s[]){ int p = Root; for(int i=0;s[i];i++){ int data = s[i]-'a'; if(tree[p].next[data]==-1){//不存在该结点 init(tree[k],data); tree[p].next[data] = k; k++; } p = tree[p].next[data]; } tree[p].count++; } queue<node> q; void AC_automation(){ q.push(tree[Root]); while(!q.empty()){ node k = q.front(); q.pop(); for(int j=0; j<cha; j++){ if( k.next[j]!=-1 ){ if( k.data == -1 ) tree[k.next[j]].fail = Root; else{ int t = k.fail; while( t!=Root && tree[t].next[j]==-1 ) t = tree[t].fail; tree[ k.next[j] ].fail = max( tree[t].next[j], Root ); } q.push(tree[k.next[j]]); } } } } int get_ans(char s[]){ int k=Root, ans = 0; for(int i=0;s[i];i++){ int t = s[i] - 'a'; while(tree[k].next[t]==-1 && k ) k = tree[k].fail; k = tree[k].next[t]; if(k==-1){ k = Root;continue;} int j = k; while( tree[j].count ){ ans += tree[j].count; tree[j].count = 0; j = tree[j].fail; } //下面两句很重要,如果走到头以后当前字母不是关键字终点然而其fail指针指向字母是关键字终点的话, //应当加入此关键值,而网上大多数程序忽视了这一点导致hdu的discuss里反例过不了 ans += tree[ tree[j].fail ].count; tree[ tree[j].fail ].count = 0; } return ans; } char tar[2*N]; int main(){ int T,n; scanf("%d",&T); while(T--){ scanf("%d",&n); init(tree[Root],-1); char a[55]; while(n--){ scanf("%s",a); Insert(a); } AC_automation(); scanf("%s",tar); printf("%d\n",get_ans(tar)); } return 0; }
相关文章推荐
- 【剑指offer】栈的压入、弹出序列
- jquery正则表达式验证手机号格式与Email
- G2P(单词到音素)的深度学习训练测试
- 创建文件目录
- this.button1.Click += new System.EventHandler(this.button1_Click);
- 北京-标哥的XMPP
- Java实现一个小说采集程序的简单实例
- java web 敏感字符过滤器
- REDIS集群处理
- find命令
- 回车enter发生的时间
- 当时钟事件声明为过程变量 让system.threading.timer时钟失效
- MyEclipse快捷键大全
- 【最短系列】C++ namespace
- 用JAVA实现网络数据包嗅探
- 在Beyond Compare中同步压缩文件夹的方法
- Javascript闭包与函数柯里化浅析
- 自定义控件—仿IOS7适用于Android的滑动开关
- 【BitMail】A Peer-to-Peer Instant Messenger Client
- Javascript :事件