AC自动机(KMP+字典树)
题目:输入N个串,判断有多少个搜索串的子串
In out
1 4
7
a
ab
abc
abcd
abcde
abcdef
abcdefg
abcd
#include<bits/stdc++.h>
using namespace std;
char str[1000000+100];
struct node{
int count; //当前结点有多少个字符串共同享用
struct node *next[26]; //指向26个字母的指针
struct node *fail; //失配指针
void init(){ //构造函数
for(int i = 0; i < 26; i++) next[i] = NULL;
count = 0;
fail = NULL;
}
} *root;
void insert(){
int len, k; //开始建树
node *p = root; //先把指针指向根
len = strlen(str); //求出串长
for(k = 0; k < len; k++){ //遍历一次字符串
int pos = str[k] - 'a'; //读出当前字符在字母表中的位置
if( p->next[pos] == NULL ){ //如果为空则开辟新结点,初始化,P指向往下指
p->next[pos] = new node;
p->next[pos]->init();
p = p->next[pos];
}
else //即使忆开辟,也要往下指
p = p->next[pos];
}
p->count++; //当前结点使用次数加一,注意是最后字符的结点才加!!
}
void getfail()
{
int i;
node *p = root, *son, *temp; //指向根的指针,儿子指针,临时指针
queue <struct node *> que; //广搜
que.push(p); //把根压入队列
while( !que.empty() ){ //只要队列不为空就就循环
temp = que.front(); //读出最前面的结点
que.pop(); //从队列删去
for(i = 0; i < 26; i++){
son = temp->next[i]; //遍历一次全部儿子,每次记为SON
if(son != NULL){ //存在这个儿子
if(temp == root) {son->fail = root;} //temp是根则son失配时必指向根
else{
p = temp->fail; //读出temp的失配指针
while( p ) { //除了根肯定不为空
if(p->next[i]){ //如果temp失配指针结点有一样的儿子
son->fail=p->next[i]; //则son指向那个儿子
break;
}
p=p->fail; //如果没有这个儿子就递归失配!
}
if(!p) son->fail=root; //广搜下失配指针为空的只有根故son指向根
}
que.push(son);//把指向这个儿子的指针压入队列
}
}
}
}
void query()
{
int len, i, cnt = 0;
len = strlen(str);
node *p, *temp;
p = root;
for( i = 0; i < len; i++)
{
int pos = str[i]-'a';
while( !p->next[pos]&&p!=root )//因为根是没有失配指针的
p = p->fail;//递归失配
p = p->next[pos];//访问儿子
if( !p ) p=root;//没有这个儿子就回到根开始
temp = p;//保存当前扫到的结点P,用TEMP来计算
while( temp!=root )
{
if(temp->count >= 0)
{
cnt += temp->count;
temp->count = -1;
}
else break;
temp = temp->fail;//当前结点的所有失配点的数量都会被计算,因为本题是求有几个串是模板串的子串
}
}
printf("%d\n",cnt);
}
int main()
{
int cas,n; //案例数
scanf("%d",&cas);
while(cas--)
{
root=new node;
root->init();
root->fail=NULL;
scanf("%d",&n); //一共有多少个子串
int i;
getchar(); //吸收回车符
for(i=0;i<n;i++)
{
gets(str); //输入N个子串并插入字典树,str全局变量不用传参
insert();
}
getfail(); //计算失配指针
gets(str); //输入搜索串
query(); //询问搜索串出出现,子串的次数
}
return 0;
}