您的位置:首页 > 其它

{模板}AC自动机

2017-11-29 19:23 330 查看
先贴一个大白书的代码

来自这篇blog

//HDU2222
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=500500;
struct ACautomachine
{
int chd
[26];//孩子节点编号
int cnt
;//当前结点 表示字符串个数
int fail
;//失配指针
int last
,sz,ans;//题目需要
void init()
{
sz=1,ans=0;
memset(cnt,0,sizeof(cnt));
memset(fail,0,sizeof(fail));
memset(chd[0],0,sizeof(chd[0]));
}
void insert(char* p)//构建trie
{
int cur=0;
for(;*p;p++)
{
if(!chd[cur][*p-'a'])
{
memset(chd[sz],0,sizeof(chd[sz]));
chd[cur][*p-'a']=sz++;
}
cur=chd[cur][*p-'a'];
}
cnt[cur]++;
}
bool query(char* p)//题目需要
{
int cur=0;
for(;*p;p++)
{
if(!chd[cur][*p-'a']) break;
cur=chd[cur][*p-'a'];
}
return cnt[cur]&&(!(*p));
}
int getFail()
{
queue<int> q;
fail[0]=0;
for(int c=0;c<26;c++)
{
int u=chd[0][c];
if(u)
{
fail[u]=0/*Null*/;
q.push(u);
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();
q.pop();
for(int c=0;c<26;c++)
{
int u=chd[r][c];
if(!u)
{
//直接指向 fail
//也就是 把 trie树 的 chd[fail[r]][c]及其子孙 全部 “复制” 作r点的子孙
chd[r][c]=chd[fail[r]][c];
continue;
}
q.push(u);
int v=fail[r];
while(v&&!chd[v][c]) v=fail[v];
//1. 令指针为 fail[fa[u]]
//2. 若指针的一级儿子中存在一点(代表字符)与 u 相同
//  则令fail[u] 指向 当前指针的该儿子
//3. 否则 指针指向 fail[指针] 并重复 2 操作、

//目的:使得当前点及其到根的路径(即一个字典串) 与 fail 和fail[fail]... 所代表字典串 后缀相同
// 从而实现重新匹配

fail[u]=chd[v][c];
last[u]=cnt[fail[u]] ? fail[u] : last[fail[u]];
}
}
}
void solve(int j)  //题目需要
{
if(!j) return;
if(cnt[j])
{
ans+=cnt[j];
cnt[j]=0;
}
solve(last[j]);
}
void find(char* T)  //题目需要
{
int n=strlen(T),j=0;
getFail();
for(int i=0;i<n;i++)
{
j=chd[j][T[i]-'a'];
if(cnt[j]) solve(j);
else if(last[j]) solve(last[j]);
}
}
}ac;

int main()
{
int t,n;
char dic[100],str[1100000];
scanf("%d",&t);
while(t--)
{
ac.init();
scanf("%d",&n);
while(n--)
{
scanf("%s",dic);
ac.insert(dic);
}
scanf("%s",str);
ac.find(str);
printf("%d\n",ac.ans);
}
return 0;
}


自己的

刚开始一点也不注意常数

TLE了好久啊[淚]

#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fo(i,x,y) for (int i=(x);i<=(y);++i)
#define fd(i,x,y) for (int i=(x);i>=(y);--i)
#define oo 2139062143
using namespace std;
typedef long long ll;
typedef double db;
const int N=501000,C=27;
int T,n;
int ans;
char dic[55],str[1100000];
struct AcAutoMation{
int d
;
int chd
[C];
int ot
;
int fail
,next
,last
;
int bz
;
int sz;
void del(int x)
{
next[last[x]]=next[x],last[next[x]]=last[x];
bz[x]=1;
}
void init()
{
memset(bz,0,sizeof bz);
memset(chd[0],0,sizeof chd[0]);
memset(ot,0,sizeof ot);
memset(fail,0,sizeof fail);
sz=0;
}
void insert(char *p)
{
int tmp=0;
int len=strlen(p+1);
fo(i,1,len)
{
int now=p[i]-'a';
if(!chd[tmp][now])
{
chd[tmp][now]=++sz;
memset(chd[sz],0,sizeof(chd[sz]));
}
tmp=chd[tmp][now];
}
++ot[tmp];
}
void Getfail()
{
int tmp=0;
int hd=0,tl=0;
fo(i,0,25)
{
if(chd[0][i])
{
d[++tl]=chd[0][i];
fail[chd[0][i]]=0;
}
}
while(hd++<tl)
{
tmp=d[hd];
fo(i,0,25)
if(chd[tmp][i])
{
d[++tl]=chd[tmp][i];
int to=fail[tmp];
while(to!=0&&!chd[to][i]) to=fail[to];
fail[chd[tmp][i]]=chd[to][i];
next[chd[tmp][i]]=(ot[chd[tmp][i]])?(fail[chd[tmp][i]]):(next[fail[chd[tmp][i]]]);
}
}
}
void solve(char *p)
{
int tmp=0;
int len=strlen(p+1);
fo(i,1,len)
{
int now=p[i]-'a',to=tmp;
while(!chd[to][now]&&to) to=fail[to];
tmp=chd[to][now];
for (int pp=tmp;pp;pp=next[pp])
{
if(ot[pp])
{
ans+=ot[pp],ot[pp]=0;
}
}
}
}
}ac;
int main()
{
int TT=clock();
scanf("%d\n",&T);
while(T--)
{
ac.init();
scanf("%d\n",&n);
fo(i,1,n)
{
scanf("%s\n",dic+1);
ac.insert(dic);
}
ac.Getfail();
ans=0;
scanf("%s\n",str+1);
ac.solve(str);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: