您的位置:首页 > 其它

hdu 2222 AC自动机模板题

2013-08-20 11:46 459 查看
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 241000
#define sigma_size 26
char s[60], t[maxn*5];
struct ac
{
int ch[maxn][sigma_size];
int val[maxn], f[maxn], last[maxn];
int next;
void init()
{
next = 0;
memset(ch[0], 0, sizeof(ch[0]));
memset(val, 0, sizeof(val));
}
void insert(char *s, int v)
{
int len = strlen(s), cur = 0;
for (int i=0; i<len; i++)
{
int idx = s[i] - 'a';
if (!ch[cur][idx])
{
ch[cur][idx] = ++next;
memset(ch[next], 0, sizeof(ch[next]));
}
cur = ch[cur][idx];
}
val[cur] += v;
}
void getFail()
{
queue<int>q;
f[0] = 0;
//初始化队列
for (int i=0; i<sigma_size; i++)
if ( ch[0][i] )
{
f[ ch[0][i] ] = 0;//第一个字母匹配失败只能指向0
last[ ch[0][i] ] = 0;//last后缀也只能指向0
q.push(ch[0][i]);
}
while (!q.empty())
{
int cur = q.front();
q.pop();
for (int i=0; i<sigma_size; i++)
{
int u = ch[cur][i];
//                        if (!u)//u结点下i位置没有字母
//                              continue;//继续下一个位置
if (!u)
{
ch[cur][i] = ch[ f[cur] ][i];
continue;
}
q.push(u);
int j = f[cur];//失败指针
while (j && !ch[j][i])//沿着失败指针走,ch[j][i]=0时没有此结点故继续
j = f[j];
f[u] = ch[j][i];//计算出结点u的失败指针
last[u] = val[ f[u] ] ? f[u] : last[ f[u] ];//f[u]处是否是单词结点
}
}
}
void getfail()
{
queue<int>q;
q.push(0);//根结点入队
while (!q.empty())
{
int cur = q.front();//取对头
q.pop();
for (int i=0; i<sigma_size; i++)
{
int u = ch[cur][i];
if (u)//u是否存在
{
if (cur==0)//如果父亲结点是根结点,失败指针和后缀链接指向0
f[u] = last[u] = 0;
else
{
int j = f[cur];//父亲的失败指针
while (j && !ch[j][i])//沿着父亲的失败指针走
j = f[j];
f[u] = ch[j][i];//找到u的失败指针
last[u] = val[ f[u] ] ? f[u] : last[ f[u] ];//f[u]处是否是单词结点
}
q.push( ch[cur][i] );
}
else
ch[cur][i] = ch[ f[cur] ][i];//不存在这一点,指向父亲结点的失败指针的第i个儿子
}
}
}
int find(char *t)
{
int len = strlen(t), j = 0, ans = 0, temp;
for (int i=0; i<len; i++)
{
int idx= t[i] - 'a';
//                  while (j && !ch[j][idx])//沿着失败指着走
//                        j = f[j];
j = ch[j][idx];//找到重新匹配的结点
temp = j;
while (temp && val[temp])//该结点是单词
{
ans += val[temp];//计数
val[temp] = 0;//标记已算过
temp = last[temp];//查找后缀串
}
}
return ans;
}
}ac;
int main()
{
int n, ncase;
scanf("%d", &ncase);
while (ncase--)
{
scanf("%d", &n);
ac.init();
for (int i=0; i<n; i++)
{
scanf("%s", s);
ac.insert(s, 1);
}
ac.getFail();
scanf("%s", t);
printf("%d\n", ac.find(t));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: