您的位置:首页 > 其它

杭电ACM1277——全文检索~~AC自动机算法

2015-07-22 22:42 253 查看
题目的意思:给你一篇文章,再给你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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: