//HDU2222
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std ;
const int maxn = 1e7 + 5 ;
//匹配字符串的个数
int cnt ;
//字典树树节点
struct node{
//字典树下一层节点
node * next[26] ;
//与字典树当前节点代表的字符相同的字符的位置,该位置是树的前缀和字符串该位置的后缀的最大匹配
node * fail ;
//该节点是否是单词的结尾以及单词的个数,比如ab、ab、abc,b位sum =2
int sum ;
};
//根节点
node * root ;
node * newnode ;
//BFS数组
node * q[maxn] ;
int head , tail ;
int N ;
//模式串和匹配串
char key[70] ;
char pattern[maxn] ;
//构建 字典树|Trie树|前缀树|单词查找树
void insert( char * s){
node * p = root ;
for(int i = 0 ;s[i] ;i ++){
int x = s[i] - 'a' ;
if( p->next[x] == NULL){
newnode = ( node * ) malloc( sizeof ( node ) ) ;
for(int j = 0 ; j< 26 ;j++)
newnode->next[j] = 0 ;
newnode->sum = 0 ;
newnode->fail = 0 ;
p->next[x] = newnode ;
}
p = p->next[x] ;
}
p->sum ++ ;
}
//构建 失配指针fail指针
void build(){
//使用BFS
head = 0 ;
tail =1 ;
q[head] = root ;
node * p ;
node * temp ;
while( head < tail ){
temp = q[head ++] ;
for( int i = 0 ; i<= 25 ;i++){
//如果temp位的后一位存在
if( temp->next[i]){
//如果temp为根节点,他的fail指向自己
if( temp == root)
temp->next[i]->fail = root ;
else{
//如果为中间节点 , p指向和temp位字符相同的位置
p = temp->fail ;
while( p ){
//用i表示一个字符
//temp后面的字符为i的字符的fail指针指向p位置的后面的字符为i的位置,后面字符相同
if( p->next[i]){
temp->next[i]->fail = p->next[i] ;
break ;
}
p = p->fail ;
}
if( p == NULL) temp->next[i]->fail = root ;
}
//BFS扩展temp的子节点
q[tail ++] = temp->next[i] ;
}
}
}
}
//多模匹配
void ACAT( char * ch){
node * p = root ;
int len = strlen( ch ) ;
for( int i = 0 ; i< len ;i++){
int x = ch[i] - 'a' ;
//对于字符x,在字典树里找到和他匹配的位置
while( !p->next[x] && p!= root) p= p->fail ;
p = p->next[x] ;
//如果没有匹配的,就从根节点开始匹配
if( !p ) p = root ;
node* temp = p ;
while ( temp != root) {
//如果temp是叶节点,则表示匹配了一次模式串
if( temp -> sum >= 0 ){
cnt += temp->sum ;
//temp->sum = -1改变了字典树的结构,但是是为了防止在匹配串里面再次匹配造成重复计算
temp->sum = -1 ;
}
else break ;
//对于abc 和bc两个模式串,他们的结尾字符相同,是两个不同的字符串,所以需要丢弃a字符,用temp= temp->fail 匹配bc字符串
temp = temp->fail ;
}
}
}
int main(){
int T ;
scanf("%d" , & T) ;
while( T--){
root = ( node * ) malloc( sizeof( node) ) ;
for ( int j = 0 ; j< 26 ;j++)
root->next[j] = 0 ;
root->fail = 0 ;
root->sum = 0 ;
scanf("%d" , &N) ;
getchar() ;
for(int i = 1 ;i<= N ; i++){
gets(key) ;
insert(key) ;
}
gets(pattern) ;
cnt = 0 ;
build() ;
ACAT(pattern) ;
printf("%d\n",cnt) ;
}
return 0 ;
}
AC自动机
最新推荐文章于 2024-06-18 12:51:06 发布