AC自动机模板
2017-11-25 16:14
323 查看
昨天晚上来基地看了看AC自动机,大概知道是怎么回事了,敲了一遍kuangbin的模板,还是可以理解的,下面就是对其模板的解析。
/*求目标串中出现了多少个模式串*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
const int maxn = 1e4+10;
const int maxl = 50+10;
const int maxm = 1e6+10;
int n;
char P[maxl];//模式串
char T[maxm];//主串
struct Trie{
int nxt[maxn*maxl][26];//Trie树
int fail[maxn*maxl];//前缀指针,在字符串失配时确定转移的结点
int end[maxn*maxl];//表示当前位置的结点是不是某个单词的结束结点
int root, L;//根结点,当前结点
//给Trie树新建一个结点
int newnode()
{
for( int i = 0; i < 26; i++)//新建结点的子节点都为空
nxt[L][i] = -1;
end[L++] = 0;//非结束结点
return L-1;//返回当前结点数
}
//Trie树初始化
void init()
{
L = 0;//树空
root = newnode();//新建一个根节点
}
// 向Trie树中插入模式串
void insert( char buf[])
{
int len = strlen(buf);//模式串长度
int now = root;//从根节点开始
for( int i = 0; i < len; i++)
{
if( nxt[now][buf[i]-'a'] == -1)//当前字母的结点不存在
nxt[now][buf[i]-'a'] = newnode();//新建一个
now = nxt[now][buf[i]-'a'];//走到当前字母所在结点
}
end[now]++;//标记一下串结束的位置
}
// 建失配表
void build()
{
queue<int> Q;//队列
fail[root] = root;//根节点的fail指向自己
//这里保证根节点的子节点的fail都指向根
for( int i = 0; i < 26; i++)//遍历根节点的26个子节点
{
if( nxt[root][i] == -1)//如果子节点不存在
nxt[root][i] = root;//????
else//子节点存在
{
fail[nxt[root][i]] = root;//子节点的fail指向根节点
Q.push(nxt[root][i]);//子节点进栈
}
}
//对于子节点存在的结点
while( !Q.empty())
{
//取出栈中的结点
int now = Q.front();
Q.pop();
for( int i = 0; i < 26; i++)//遍历当前结点的子节点
{
if( nxt[now][i] == -1)//子节点不存在
nxt[now][i] = nxt[fail[now]][i];//????
else
{
fail[nxt[now][i]] = nxt[fail[now]][i];//当前结点的fail沿着父亲的fail走,指向父亲fail的与自己值相同的子节点
Q.push(nxt[now][i]);//当前结点进栈
}
}
}
}
int query( char buf[])
{
int len = strlen(buf);//主串的长度
int now = root;//指向根节点
int res = 0;
for( int i = 0; i < len; i++)//遍历主串
{
now = nxt[now][buf[i]-'a'];//当前字符在Trie树中的位置
int tmp = now;
while( tmp != root)//==的话为空,前面记录了的,!=代表存在
{
res += end[tmp];//看是否为一个完整的串,是的话就加到res里
end[tmp] = 0;//标记已经计算过
tmp = fail[tmp];//指向fail指针
}
}
return res;
}
};
char buf[1000000];
Trie ac;
int main()
{
int T_T;
scanf("%d",&T_T);
while( T_T--)
{
scanf("%d",&n);
ac.init();
for( int i = 0; i < n; i++)
{
scanf("%s",P);
ac.insert(P);
}
ac.build();
scanf("%s",T);
printf("%d\n",ac.query(T));
}
return 0;
}
/*求目标串中出现了多少个模式串*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
const int maxn = 1e4+10;
const int maxl = 50+10;
const int maxm = 1e6+10;
int n;
char P[maxl];//模式串
char T[maxm];//主串
struct Trie{
int nxt[maxn*maxl][26];//Trie树
int fail[maxn*maxl];//前缀指针,在字符串失配时确定转移的结点
int end[maxn*maxl];//表示当前位置的结点是不是某个单词的结束结点
int root, L;//根结点,当前结点
//给Trie树新建一个结点
int newnode()
{
for( int i = 0; i < 26; i++)//新建结点的子节点都为空
nxt[L][i] = -1;
end[L++] = 0;//非结束结点
return L-1;//返回当前结点数
}
//Trie树初始化
void init()
{
L = 0;//树空
root = newnode();//新建一个根节点
}
// 向Trie树中插入模式串
void insert( char buf[])
{
int len = strlen(buf);//模式串长度
int now = root;//从根节点开始
for( int i = 0; i < len; i++)
{
if( nxt[now][buf[i]-'a'] == -1)//当前字母的结点不存在
nxt[now][buf[i]-'a'] = newnode();//新建一个
now = nxt[now][buf[i]-'a'];//走到当前字母所在结点
}
end[now]++;//标记一下串结束的位置
}
// 建失配表
void build()
{
queue<int> Q;//队列
fail[root] = root;//根节点的fail指向自己
//这里保证根节点的子节点的fail都指向根
for( int i = 0; i < 26; i++)//遍历根节点的26个子节点
{
if( nxt[root][i] == -1)//如果子节点不存在
nxt[root][i] = root;//????
else//子节点存在
{
fail[nxt[root][i]] = root;//子节点的fail指向根节点
Q.push(nxt[root][i]);//子节点进栈
}
}
//对于子节点存在的结点
while( !Q.empty())
{
//取出栈中的结点
int now = Q.front();
Q.pop();
for( int i = 0; i < 26; i++)//遍历当前结点的子节点
{
if( nxt[now][i] == -1)//子节点不存在
nxt[now][i] = nxt[fail[now]][i];//????
else
{
fail[nxt[now][i]] = nxt[fail[now]][i];//当前结点的fail沿着父亲的fail走,指向父亲fail的与自己值相同的子节点
Q.push(nxt[now][i]);//当前结点进栈
}
}
}
}
int query( char buf[])
{
int len = strlen(buf);//主串的长度
int now = root;//指向根节点
int res = 0;
for( int i = 0; i < len; i++)//遍历主串
{
now = nxt[now][buf[i]-'a'];//当前字符在Trie树中的位置
int tmp = now;
while( tmp != root)//==的话为空,前面记录了的,!=代表存在
{
res += end[tmp];//看是否为一个完整的串,是的话就加到res里
end[tmp] = 0;//标记已经计算过
tmp = fail[tmp];//指向fail指针
}
}
return res;
}
};
char buf[1000000];
Trie ac;
int main()
{
int T_T;
scanf("%d",&T_T);
while( T_T--)
{
scanf("%d",&n);
ac.init();
for( int i = 0; i < n; i++)
{
scanf("%s",P);
ac.insert(P);
}
ac.build();
scanf("%s",T);
printf("%d\n",ac.query(T));
}
return 0;
}
相关文章推荐
- HDu-2896 病毒侵袭,AC自动机模板题!
- HDU 2896 病毒侵袭 (AC自动机模板)
- 病毒侵袭(我的第二道AC自动机(模板进一步升级完善))
- hdu 2222 AC自动机模板题(指针版+数组版)
- LA 4670 (AC自动机 模板题) Dominating Patterns
- AC自动机模板
- 病毒侵袭(ac自动机模板)
- 病毒侵袭持续中---hdu3065(AC自动机模板)
- AC自动机算法及模板
- [模板] - AC自动机 - 动态 - 感谢小太阳
- hdu 2222:Keywords Search(AC自动机模板)
- P3796 【模板】AC自动机(加强版)
- 杭电2896题 AC自动机模板题
- 模板 AC自动机
- 【洛谷】3796 【模板】AC自动机(加强版)
- AC自动机 - 多模式串的匹配 --- HDU 3695 Computer Virus on Planet Pandora(模板题)
- AC自动机 ( 静态建树模板 )——Substring ( UVA 11468 )
- HDU 2222 AC自动机模板
- HDOJ 2222 AC自动机模板题
- HDOJ 2222 - Keywords Search 更新AC自动机模板...用类来表示