1.题目链接。题目大意:给定多个单词,一段文本,找出这段文本中出现过多少个给定的单词。要是单词只有一个,直接KMP完事,但是单词多个就不行了,这是典型的多模式匹配算法。对于多模式匹配算法,我也是刚刚学了,因为之前字符串算法都是交给其他的队友完成。推荐文章:https://www.cnblogs.com/cmmdc/p/7337611.html。
里面写了AC自动机的详解:其实就是树上KMP完事。
2.这个题就是AC自动机的裸题了。
#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int maxn = 500010;
#pragma warning(disable:4996)
struct AC_automation
{
int nxt[maxn][26], fail[maxn], end[maxn];
int root, L;
int newnode()
{
for (int i = 0; i < 26; i++)nxt[L][i] = -1;
end[L++] = 0;
return L - 1;
}
void init()
{
L = 0;
root = newnode();
}
void insert(char buf[])
{
int len = strlen(buf);
int now = root;
for (int i = 0; i < len; i++)
{
int x = buf[i] - 'a';
if (nxt[now][x] == -1)nxt[now][x] = newnode();
now = nxt[now][x];
}
end[now]++;
}
void build()
{
queue<int>que;
fail[root] = root;
for (int i = 0; i < 26; i++)
{
if (nxt[root][i] == -1)nxt[root][i] = root;//
else//在trie树上已经村的得点,并且
{
int x = nxt[root][i];
fail[x] = root;
que.push(x);
}
}
//开始广度搜素
while (!que.empty())
{
int now = que.front();
que.pop();
for (int i = 0; i < 26; i++)
{
if (nxt[now][i] == -1)
nxt[now][i] = nxt[fail[now]][i];
else
{
int x = nxt[now][i];
fail[x] = nxt[fail[now]][i];
que.push(x);
}
}
}
}
int query(char buf[])
{
int len = strlen(buf);
int now = root;
int res = 0;
for (int i = 0; i < len; i++)
{
now = nxt[now][buf[i] - 'a'];
int tmp = now;
while (tmp != root)
{
res += end[tmp];
end[tmp] = 0;
tmp = fail[tmp];
}
}
return res;
}
};
char buf[maxn * 2];
AC_automation ac;
int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
ac.init();
for (int i = 0; i < n; i++)
{
scanf("%s", buf);
ac.insert(buf);
}
ac.build();
scanf("%s", buf);
printf("%d\n", ac.query(buf));
}
return 0;
}