度娘讲的很好……所以不懂就百度吧。。。
首先构造一颗trie,
然后bfs构造fail指针。
最后进行文章匹配,注意题目只要求出现出现几个关键字。
所以只要找到一个就标记一下,下次再找到不算。
比如
1
1
abc
abcabc
输出1
还有,单词有可能重复,
1
2
abc
abc
abc
输出2
#include<cstring>
#include<queue>
#define MAXN 1000000
#define SIG 26
using namespace std;
char str[MAXN];
int size, ans;
struct node {
int fail, cnt, next[SIG];
bool vis;
void Init() {
fail = cnt = 0;
vis = false;
memset(next, 0, sizeof(next));
}
};
node trie[MAXN];
inline int get(char ch) {
return ch - 'a';
}
void insert(char *s) {
int now, t;
for (now = 0; *s; s++) {
t = get(*s);
if (!trie[now].next[t]) {
trie[++size].Init();
trie[now].next[t] = size;
}
now = trie[now].next[t];
}
trie[now].cnt++; //记录以该结点为结束点的单词个数
}
void bfs() {
int now, i, temp;
queue<int> q;
q.push(0);
while (!q.empty()) {
now = q.front();
q.pop();
for (i = 0; i < SIG; i++) {
if (trie[now].next[i]) {
temp = trie[now].next[i];
if (now)
trie[temp].fail = trie[trie[now].fail].next[i];
q.push(temp);
} else
trie[now].next[i] = trie[trie[now].fail].next[i];
}
}
}
int find(char *str)
{
int ans=0;
for(int now=0;*str;str++)
{
int j=get(*str);
now=trie[now].next[j];
int tmp=now; //将当前点保存下来
while(tmp&&(~trie[tmp].cnt)) //顺着失配边找,把路上的值都加起来
{
ans+=trie[tmp].cnt;
trie[tmp].cnt=-1; //因为题目要求,只要找到一个关键字就可以了,下次再找到也无视它
tmp=trie[tmp].fail;
}
}
return ans;
}
int main()
{
int t,n;
scanf("%d",&t);
char a[60];
while(t--)
{
size=0;
trie[0].Init();
scanf("%d",&n);
while(n--)
{
scanf("%s",a);
insert(a);
}
bfs();
scanf("%s",str);
printf("%d\n",find(str));
}
return 0;
}