AC自动机入门-poj3461解法
来源:互联网 发布:vb语言用处 编辑:程序博客网 时间:2024/05/19 15:19
前提 :
1. KMP 单模式匹配原理
2. 字典树结构
失配函数获取:
1. 找当前点s的失配节点下标为c, 先找到找父节点f的失配节点fail[f], 如果fail[f]存在下标为c子节点, 那么fail[s] = ch[fail[f]][c]
不存在沿着失配指针回推fail[….fail[f]]直至根节点
2. 由于是树形, 所以一般采取bfs递推fail值, 而不是KMP的线性递归
3. 实现过程 :
1) 根节点的子结点fail值全为0, 入队
2) 第三层开始, bfs入队, 回推fail(找父节点fail, KMP思想)
ps:还可以记下以该节点为尾的字符串的最大后缀串(模板式串中存在的)
比如如果有3个模式串AZAZAB, AZA, ZA那么 第一个串的最后一个‘A’的last值应该是AZA的最后一个‘A’的节点下标, 这也说明多模式串中同一个节点可能对应多个串的串尾
code:
struct AC_Auto{ int ch[10010][26], last[10010], val[10010], f[10010]; string tmp[10010];/**存节点字符串*/ int sz; int idx(char s){return s - 'A';} AC_Auto(){ memset(ch, 0, sizeof ch); sz = 1; memset(val, 0, sizeof val); memset(last, 0, sizeof last);/**初始化*/ memset(f, 0, sizeof f); } void insert(string w){/**一般字典树建树*/ int u = 0; for(int i = 0; w[i]; ++i){ int c = idx(w[i]); if(!ch[u][c]){ ch[u][c] = sz++; } u = ch[u][c]; } val[u] = 1; tmp[u] = w;/**标记单词, 记下单词*/ } void getFail(){ queue<int> q; q.push(0);/**头结点*/ while(!q.empty()){ int t = q.front(); q.pop(); for(int c = 0; c < 26; ++c){ if(ch[t][c]){/**子节点*/ int u = ch[t][c], v = f[t]; q.push(u); while(v && !ch[v][c]) v = f[v];/**回推获取失配/ /**这里如果退回到根节点, 根节点下标为c节点也可能存在*/ f[u] = t ? ch[v][c] : 0;/**第二层直接fail = 0*/ last[u] = val[f[u]] ? f[u] : last[f[u]]; /**获取last*/ cout << "u : " << u << " " << last[u] << endl; } } } } int query(){ int u = 0; for(int i = 0; s[i]; ++i){ int c = idx(s[i]); while(u && !ch[u][c]) u = f[u]; u = ch[u][c];/**查询*/ if(val[u]) print(u);/**找到一个单词*/ else if(last[u]) print(last[u]);/**找到模式串中该节点表示字符串最大后缀的单词*/ } return 1; } void print(int x){/**递归打印*/ if(x){ cout << tmp[x] << endl; print(last[x]); } }};
POJ 3461 AC自动机解法
#include <iostream>#include <cstring>#include <queue>using namespace std;const int N = 1000010;char s[N], w[10010];struct AC_Auto{ int ch[10010][26], last[10010], val[10010], f[10010]; int sz; int idx(char s){return s - 'A';} AC_Auto(){ memset(ch, 0, sizeof ch); sz = 1; memset(val, 0, sizeof val); memset(last, 0, sizeof last); memset(f, 0, sizeof f); } void insert(){ int u = 0; for(int i = 0; w[i]; ++i){ int c = idx(w[i]); if(!ch[u][c]){ ch[u][c] = sz++; } u = ch[u][c]; } val[u] = 1; } void getFail(){ queue<int> q; q.push(0); while(!q.empty()){ int t = q.front(); q.pop(); for(int c = 0; c < 26; ++c){ if(ch[t][c]){ int u = ch[t][c], v = f[t]; q.push(u); while(v && !ch[v][c]) v = f[v]; f[u] = t ? ch[v][c] : 0; last[u] = val[f[u]] ? f[u] : last[f[u]]; } } } } int query(){ int u = 0, ans = 0; for(int i = 0; s[i]; ++i){ int c = idx(s[i]); while(u && !ch[u][c]) u = f[u]; u = ch[u][c]; if(val[u]) ++ans, u = f[u];/**找到之后回退失配节点, 同裸KMP*/ } return ans; }};int main(){ int t; cin >> t; while(t--){ cin >> w >> s; AC_Auto ac; ac.insert(); ac.getFail(); cout << ac.query() << endl; } return 0;}
0 0
- AC自动机入门-poj3461解法
- AC自动机入门
- HDU2222 AC自动机入门
- hdu2222(AC自动机入门)
- AC自动机入门
- AC自动机入门
- AC自动机入门
- AC自动机入门
- AC自动机入门
- uvalive 3490 解法二 AC自动机 + 高斯消元
- hdu2222之AC自动机入门
- 算法入门之AC自动机
- POJ 1204 AC自动机入门
- hdu 2222 AC自动机入门
- HDU2222 AC自动机 入门模板
- hdu 2222 -AC自动机入门
- AC自动机入门题目(HDU
- AC自动机算法详解(入门)
- c++学习——构造函数与析构函数
- MySql insert一条数据时使用自增主键,并在返回对象中给ID赋值
- JS中控制两个div的高度保持一致
- brew和brew-cask安装
- openstack调整虚拟机规格和热迁移自动确认
- AC自动机入门-poj3461解法
- Saruman's Army POJ
- 性能测试前期,如何对一个系统的并发量进行评估?
- ios 仿京东商品属性选择界面
- CollapsingToolbarLayout及Toolbar
- 图片内容在不同分辨率下居中显示
- Hrbust 1000 A + B Problem【明天校赛加油~】
- es scroll size 设置问题
- 博客开通序