题目的意思:给你一篇文章,再给你T个字符串,判断这T个字符串有哪些在文章中出现过。
由于文章很大,普通的方法必定超时,所以需要用 AC自动机算法。
AC自动机算法是多模匹配算法之一,主要是用于在一篇文章中,找出给定的N个单词在这篇文章中出现的个数。
AC自动机算法,我也是刚刚学习,主要是在建立字典树的基础上,增加了失败指针,提高了匹配的效率。而且最难的是失败指针的建立。
它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高。
对于AC自动机算法,可以参考大神的博客:点击打开链接 里面有详细的说明,我也是从中学习的。
AC自动机算法,基本上就是那样子的,所以,写的代码,可以成为模版来用。
我一开始用的不是队列来做的,也就是参考上面博客的大神写的,但是,内存超了,所以,改用了队列来做,才过的,而且用的内存也仅仅只是比规定的少了100多K。
下面的是AC的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
char str[60010];
class data
{
public:
int key; //判断是否是叶子结点
data *fail; //失败指针
data *num[10]; //子结点
data() //构造函数
{
key = 0;
fail = NULL;
memset(num, NULL, sizeof(num));
}
};
int head, tail;
vector <int> ans;
bool flag;
void buildTree(data *root, int x, char *p) //建立字典树函数,root提前new了一个
{
int j;
int length = strlen(p);
data *temp = root;
for(j = 0; j < length; j++)
{
int k = p[j] - '0';
if(temp->num[k] == NULL)
{
temp->num[k] = new data();
}
temp = temp->num[k];
}
temp->key = x;
}
void get_fail(data *head) //获取fail指针
{
data *now, *p;
queue<data*> q;
head->fail = NULL;
q.push(head); //根节点入队
for(; !q.empty(); )
{
now = q.front();
q.pop();
for(int i = 0; i < 10; ++i) //所有不为NULL的入队
if(now->num[i])
{
p = now->fail;
for(; p && !p->num[i]; p = p->fail);
now->num[i]->fail = p ? p->num[i] : head;
q.push(now->num[i]);
}
}
}
void finds(data *root, char *s) //匹配函数
{
int leng = strlen(s);
data *p = root;
for(int i = 0; i < leng; i++)
{
int k = s[i] - '0';
while(!p->num[k] && p != root)
p = p->fail;
p = p->num[k] == NULL ? root : p->num[k];
data *temp = p;
for( ; temp != root; temp = temp->fail)
{
if(temp->key)
{
ans.push_back(temp->key);
flag = true;
}
}
}
}
int main()
{
// freopen("data.txt", "r", stdin);
int n, t, i, j, k;
char s[120];
while(cin >> n >> t)
{
getchar();
flag = false;
head = tail = 0;
data *root = new data();
memset(str, '\0', sizeof(str));
for(i = 0; i < n; i++) //输入数据
{
gets(s);
strcat(str, s);
}
getchar();
for(i = 0; i < t; i++) //输入数据
{
gets(s);
int length = strlen(s);
k = j = 0;
while(s[k++] != ']'); //去掉前面没用的
k += 1;
while(k < length)
{
s[j++] = s[k++];
}
s[j] = '\0';
buildTree(root, i + 1, s); //建树
}
get_fail(root); //获取fail指针
finds(root, str); //匹配
if(flag)
{
cout << "Found key: ";
for(i = 0; i < ans.size(); i++)
i != ans.size() - 1 ? cout << "[Key No. " << ans[i] << "] " : cout << "[Key No. " << ans[i] << "]" << endl;;
}
else
cout << "No key can be found !" << endl;
}
return 0;
}