其实这是一道AC自动机的基础入门题。所以在掌握了AC自动机之后,这道题是很容易A出来的。但是在掌握AC自动机之前,需要你有Trie,KMP的一定的了解。AC自动机我花了一个晚上才只是对代码模板有了一定的了解。AC自动机分三部分:建立Tire树,构造失败指针,查询字符串;主要是构造失败指针这一块,比较难以理解。构造失败指针就是说为当前的一个字符节点的失败指针,就要遍历该节点的父亲节点的失败指针中的儿子节点是否与该节点所代表的字符一样的指针,若没有,该节点的失败指针就指向根节点,若有,该节点的失败指针就指向儿子节点的指针。
参考学习博客链接:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
http://www.cnblogs.com/kuangbin/p/3164106.html
该道题我只是把主要的不走给写了下来,并不是正解!!!
代码如下:
//给出几个单词,在给出一个字符串,统计有多少个单词在该字符串中出现过。AC自动机
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
node *fail;
node *next[30];
int count;
node() {
fail = 0;
memset(next,0,sizeof(next));
count=0;
}
}*q[5000001];
int head=0,tail=0;
node *root=new node();
void insert(char s[]) {
int i=0;
node *q=root,*p;
while(s[i]) {
int val = s[i]-'a';
if(q->next[val] == 0) {
p = new node();
q->next[val] = p;
q = p;
}
else q = q->next[val];
i++;
}
q->count++;
}
void build_ac_automation() {
int i;
node *temp;
root->fail = 0;
q[head++] = root;
while(head != tail) {
temp = q[tail++];
for(i=0; i<26; i++) {
if(temp->next[i] !=0) {
if(temp == root) temp->next[i]->fail = root;
else {
node *q = temp->fail;
while(q!=0) {
if(q->next[i] != 0) {
temp->next[i]->fail = q->next[i];
break;
}
q = q->fail;
}
if(q == 0) temp->next[i]->fail = root;
}
q[head++] = temp->next[i];
}
}
}
}
int query(char s[]) {
int i=0,num=0;
node *q = root;
while(s[i]) {
int val=s[i]-'a';
while(q->next[val]==0 && q!=root) q=q->fail;
q = q->next[val];
q = (q==0) ? root: q;
node *temp=q;
while(temp!=root && temp->count!=-1) {
num+=temp->count;
temp->count=-1;
temp = temp->fail;
}
i++;
}
return num;
}
int main() {
char s[20],str[200];
int i,n;
cin>>n;
for(i=0; i<n; i++) {
cin>>s;
insert(s);
}
//cout<<i<<endl;
build_ac_automation();
cin>>str;
cout<<query(str)<<endl;
return 0;
}