poj 4052 AC自动机
2015-08-03 16:21
232 查看
题意:给定2500个模式串,和长度为5,100,000的母串,问母串中包含多少个模式串。如果模式串s1是模式串s2的子串,而且s2被母串包含,则s1应被忽略。
思路:首先比较常规,对模式串建立AC自动机。然后用母串S在trie图上遍历,如果:
1、走到未被忽略的终止节点x,则将x标记为已经匹配,并且忽略掉所有目前匹配串的所有子串。
2、走到危险但非终止的节点y, 则沿着y的前缀指针链找到第一个终止节点x,将x标记为已经匹配,并且忽略掉所有目前匹配串的所有子串。
忽略的方法就是将x的所有前缀结点flag置为0,并在trie图中x到root之间的所有结点都如此处理一遍(相当于遍历当前串的所有子串)
最后统计匹配且未被忽略的模式串数目。代码中flag数组为1表示终止结点,为2表示危险但是非终止结点,为3表示已经匹配的结点。
思路:首先比较常规,对模式串建立AC自动机。然后用母串S在trie图上遍历,如果:
1、走到未被忽略的终止节点x,则将x标记为已经匹配,并且忽略掉所有目前匹配串的所有子串。
2、走到危险但非终止的节点y, 则沿着y的前缀指针链找到第一个终止节点x,将x标记为已经匹配,并且忽略掉所有目前匹配串的所有子串。
忽略的方法就是将x的所有前缀结点flag置为0,并在trie图中x到root之间的所有结点都如此处理一遍(相当于遍历当前串的所有子串)
最后统计匹配且未被忽略的模式串数目。代码中flag数组为1表示终止结点,为2表示危险但是非终止结点,为3表示已经匹配的结点。
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <cstdlib> using namespace std; #define clc(s,t) memset(s,t,sizeof(s)) #define INF 0x3fffffff #define N 5100005 int T,n,top,len; int t [26],fail ,flag ,f ; char s ; int newnode(){ top++; for(int i = 0;i<26;i++) t[top][i] = -1; return top; } void init(){ clc(fail,0); clc(flag,0); clc(f,0); for(int i = 0;i<26;i++) t[0][i] = 1; f[1] = 0; top = 0; newnode(); } void input(){ char ch; int i; len = 0; while((ch=getchar()) && ch!='\n'){ if(ch=='['){ scanf("%d",&i); ch = getchar(); while(i--) s[len++] = ch; getchar(); }else s[len++] = ch; } s[len] = '\0'; } void insert(char* s){ int i,r = 1; for(i = 0;s[i];i++){ if(t[r][s[i]-'A'] == -1){ t[r][s[i]-'A'] = newnode(); f[top] = r; } r = t[r][s[i]-'A']; } flag[r] = 1;//为1表示是终止结点 } void buildDFA(){ int i,now; queue<int> q; q.push(1); while(!q.empty()){ now = q.front(); q.pop(); for(i = 0;i<26;i++){ if(t[now][i] == -1) t[now][i] = t[fail[now]][i]; else{ fail[t[now][i]] = t[fail[now]][i]; q.push(t[now][i]); if(!flag[t[now][i]] && flag[t[fail[now]][i]] == 1) flag[t[now][i]] = 2;//为2表示是危险结点,但是不是终止结点 } } } } void update(int x){ while(x){ flag[x] = 0; x = fail[x]; } } void match(int x){ flag[x] = 3; update(fail[x]); x = f[x]; while(x>1){ update(x); x = f[x]; } } void search(char* s){ int i,tmp,r = 1; for(i = 0;s[i];i++){ r = tmp = t[r][s[i]-'A']; if(flag[tmp] == 1) match(tmp); else if(flag[tmp] == 2){ while(tmp && flag[tmp]==2) tmp = fail[tmp]; if(flag[tmp] == 1) match(tmp); } } } int main(){ scanf("%d",&T); while(T--){ int i,res=0; init(); scanf("%d",&n); getchar(); for(i = 0;i<n;i++){ input(); insert(s); } buildDFA(); input(); search(s); for(i = 1;i<=top;i++) res+=(flag[i]==3); printf("%d\n",res); } return 0; }
相关文章推荐
- Hibernate知识点总结
- hdu 4027 Can you answer these queries? (区间线段树,区间数开方与求和,经典题目)
- js模板
- android上传图片到PHP的过程详解
- iOS手势(拖动,缩放,旋转,点击,手势依赖,自定义手势)
- php将远程图片保存到本地服务器的实现代码
- xcode基础配置
- springMail发送Text简单邮件的方法
- 杭电OJ-1001-(Sum Problem大整数求和问题)
- Java byte数组 转short int
- SVN 权限配置详细说明
- Activity生命周期(二)——多个Activity交互
- php header解决乱码问题及其他乱码问题
- oracle 日期获取
- 更新yum源/apt-get源
- 避免野指针的产生
- poj 2299
- Linux命令之ls
- hdoj2070斐波那契数列
- mysql的死锁等6个实战问题解决