题目的意思:给你一篇文章,再给你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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/qq_25425023/article/details/47010929