ac自动机提高效率的一个办法是实现后缀链接,即增加一个指针指向下一个单词节点,而不是盲目的沿着失败指针查询。
however,lightoj1427迷之超时,难道动态建树比静态建树快很多吗?再写个静态的试试吧……
TAT:我又写了个静态的,跑了2300多ms,另外struct里面能开的空间并不能很大,本机开辟int ch[505*505][26]时会编译不过。同时写会了静态和动态,对ac自动机的掌握加深了不少。后面附上AC代码
题意:求解各个模式串在文本串中出现的次数
#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1000005;
const int maxm = 505;
char s[maxn],p[maxm][maxm];
struct Node
{
Node *next[26];
Node *fail;
Node *last; //后缀链接,全靠你来优化查询了
bool isWord;
int cnt;
Node() { memset(next,0,sizeof(next)); isWord = false; fail = NULL; last = NULL; cnt = 0; }
};
Node *Q[maxn];
struct ACMachine
{
Node *root;
ACMachine() { root = new Node(); }
~ACMachine()
{
destroy(root);
}
void destroy(Node *rt)
{
if(!rt) return;
for(int i = 0; i < 26; i++)
destroy(rt->next[i]);
delete rt;
}
void Insert(char str[])
{
Node *p = root;
for(int i = 0; str[i] != 0; i++)
{
int index = str[i] - 'a';
if(p->next[index] == NULL) p->next[index] = new Node();
p = p->next[index];
}
p->isWord = true;
}
void build_ACMachine()
{
int head = 0,tail = 0;
Q[tail++] = root;
while(head < tail)
{
Node *fa = Q[head++];
for(int i = 0; i < 26; i++)
{
Node *son = fa->next[i];
if(son != NULL)
{
Node *temp = fa->fail;
while(temp != NULL && temp->next[i] == NULL) temp = temp->fail;
if(temp == NULL) son->fail = root;
else
{
son->fail = temp->next[i];
if(temp->next[i]->isWord) son->last = temp->next[i];
else son->last = temp->next[i]->last;
}
Q[tail++] = son;
}
}
}
}
void query(char str[])
{
Node *p = root;
for(int i = 0; str[i] != 0; i++)
{
int index = str[i] - 'a';
while(p != NULL && p->next[index] == NULL)
p = p->fail;
if(p == NULL) p = root;
else
{
p = p->next[index];
if(p->isWord) p->cnt++;
Node *temp = p->last;
while(temp != NULL)
{
temp->cnt++;
temp = temp->last;
}
}
}
}
int getAns(char str[])
{
Node *p = root;
for(int i = 0; str[i]; i++)
{
int index = str[i] - 'a';
p = p->next[index];
}
return p->cnt;
}
};
int main()
{
int T,cas = 1;
scanf("%d" ,&T);
while(T--)
{
int n;
scanf("%d" ,&n);
scanf("%s" ,s);
ACMachine ac;
for(int i = 0; i < n; i++)
{
scanf("%s" ,p[i]);
ac.Insert(p[i]);
}
ac.build_ACMachine();
ac.query(s);
printf("Case %d:\n",cas++);
for(int i = 0; i < n; i++)
{
printf("%d\n",ac.getAns(p[i]));
}
}
return 0;
}
AC代码:静态建ac自动机
#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1000005;
const int maxm = 505;
const int maxnode = 505*505;
char s[maxn],p[maxm][maxm];
int ch[maxnode][26];
int fail[maxnode];
bool isWord[maxnode];
int last[maxnode];
int cnt[maxnode];
int sz;
void init()
{
sz = 1;
memset(ch,0,sizeof(ch));
memset(isWord,0,sizeof(isWord));
memset(last,0,sizeof(last));
memset(fail,0,sizeof(fail));
memset(cnt,0,sizeof(cnt));
memset(p,0,sizeof(p));
memset(s,0,sizeof(s));
}
void Insert(char *str)
{
int u = 0;
for(int i = 0; str[i]; i++)
{
int index = str[i] - 'a';
if(ch[u][index] == 0) ch[u][index] = sz++;
u = ch[u][index];
}
isWord[u] = true;
}
void build_ACMachine()
{
int u = 0;
fail[u] = -1;
queue<int> q;
q.push(u);
while(!q.empty())
{
int fa = q.front();
q.pop();
for(int i = 0; i < 26; i++)
{
int son = ch[fa][i];
if(son != 0)
{
int temp = fail[fa];
while(temp != -1 && ch[temp][i] == 0) temp = fail[temp];
if(temp == -1) fail[son] = 0;
else
{
fail[son] = ch[temp][i];
if(isWord[fail[son]] == true) last[son] = fail[son];
else last[son] = last[fail[son]];
}
q.push(son);
}
}
}
}
void query(char *str)
{
int u = 0;
for(int i = 0; str[i]; i++)
{
int index = str[i] - 'a';
while(u != -1 && ch[u][index] == 0)
u = fail[u];
if(u == -1) u = 0;
else
{
u = ch[u][index];
int temp = u;
while(temp != 0)
{
if(isWord[temp])
cnt[temp]++;
temp = last[temp];
}
}
}
}
int getAns(char *str)
{
int u = 0;
for(int i = 0; str[i]; i++)
{
int index = str[i] - 'a';
u = ch[u][index];
}
return cnt[u];
}
int main()
{
int T,cas = 1;
scanf("%d",&T);
while(T--)
{
init();
int n;
scanf("%d",&n);
scanf("%s",s);
for(int i = 0; i < n; i++)
{
scanf("%s",p[i]);
Insert(p[i]);
}
build_ACMachine();
query(s);
printf("Case %d:\n",cas++);
for(int i = 0; i < n; i++)
{
printf("%d\n",getAns(p[i]));
}
}
return 0;
}