hdu 2222 Keywords Search - Aho-Corasick自动机
2016-07-26 17:52
375 查看
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 51758 Accepted Submission(s):
16671
[align=left]Problem Description[/align]
In the modern time, Search engine came into the life of
everybody like Google, Baidu, etc.
Wiskey also wants to bring this feature to
his image retrieval system.
Every image have a long description, when users
type some keywords to find the image, the system will match the keywords with
description of image and show the image which the most keywords be
matched.
To simplify the problem, giving you a description of image, and some
keywords, you should tell me how many keywords will be match.
[align=left]Input[/align]
First line will contain one integer means how many
cases will follow by.
Each case will contain two integers N means the number
of keywords and N keywords follow. (N <= 10000)
Each keyword will only
contains characters 'a'-'z', and the length will be not longer than 50.
The
last line is the description, and the length will be not longer than
1000000.
[align=left]Output[/align]
Print how many keywords are contained in the
description.
[align=left]Sample Input[/align]
[align=left]Sample Output[/align]
[align=left]Author[/align]
Wiskey
[align=left]Recommend[/align]
lcy | We have carefully selected several similar problems for you: 2896 3065 2243 2825 3341
(转自 http://acm.hdu.edu.cn/showproblem.php?pid=2222)
先讲讲大意,就是给一大堆模板串,再给一串很长的文本串,求有几个模板串在这个文本串中出现过
首先,模板串的长度较短,数量多,极其符合ac自动机的特点,就这么愉快地决定使用ac自动机(其实也并不是特别地愉快
,虽说是裸题)
接着注意几个事项
1.模板串重复出现,比如下面这组数据
2.多组数据,第一个输入的数是数据组数(这个问题应该不大)
3.如果用数组的话不要一次性用memset把整个数组都赋值,这样的话是十分浪费时间的
接着附上用指针写的AC自动机(虽说我用数组写了一个,调试了2天都没有调出来,果断重写)
Code
[后记]
附上自己调程序时所用的数据生成器,如果用随机数生成可能基本上刷个1000,2000组很多问题都不能找出来,
因为直接用随机数要刷出点神数据的概率还是比较低的
md_ks.cpp
Total Submission(s): 51758 Accepted Submission(s):
16671
[align=left]Problem Description[/align]
In the modern time, Search engine came into the life of
everybody like Google, Baidu, etc.
Wiskey also wants to bring this feature to
his image retrieval system.
Every image have a long description, when users
type some keywords to find the image, the system will match the keywords with
description of image and show the image which the most keywords be
matched.
To simplify the problem, giving you a description of image, and some
keywords, you should tell me how many keywords will be match.
[align=left]Input[/align]
First line will contain one integer means how many
cases will follow by.
Each case will contain two integers N means the number
of keywords and N keywords follow. (N <= 10000)
Each keyword will only
contains characters 'a'-'z', and the length will be not longer than 50.
The
last line is the description, and the length will be not longer than
1000000.
[align=left]Output[/align]
Print how many keywords are contained in the
description.
[align=left]Sample Input[/align]
1 5 she he say shr her yasherhs
[align=left]Sample Output[/align]
3
[align=left]Author[/align]
Wiskey
[align=left]Recommend[/align]
lcy | We have carefully selected several similar problems for you: 2896 3065 2243 2825 3341
(转自 http://acm.hdu.edu.cn/showproblem.php?pid=2222)
先讲讲大意,就是给一大堆模板串,再给一串很长的文本串,求有几个模板串在这个文本串中出现过
首先,模板串的长度较短,数量多,极其符合ac自动机的特点,就这么愉快地决定使用ac自动机(其实也并不是特别地愉快
,虽说是裸题)
接着注意几个事项
1.模板串重复出现,比如下面这组数据
1 3 aa bb aa aabbcc
2.多组数据,第一个输入的数是数据组数(这个问题应该不大)
3.如果用数组的话不要一次性用memset把整个数组都赋值,这样的话是十分浪费时间的
接着附上用指针写的AC自动机(虽说我用数组写了一个,调试了2天都没有调出来,果断重写)
Code
/* * acm.hdu.edu.cn * Problem#2222 * Accepted * Time:296ms * Memory:58152k */ #include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; #define SEG_SIZE 26 typedef class TrieNode{ public: TrieNode* next[SEG_SIZE]; TrieNode* fail; //失配指针 TrieNode* last; //后缀链接 int value; TrieNode():fail(NULL),last(NULL),value(0){ memset(next, 0, sizeof(next)); } }TrieNode; typedef class Trie { public: TrieNode* root; Trie(){ root = new TrieNode(); } static int cti(char ch){ //将字符转换成Trie树中next数组的下标 return ch - 'a'; } void insert(string s){ TrieNode *p = root; for(int i = 0;i < s.length();i++){ int c = cti(s[i]); if(p->next[c] == NULL){ TrieNode *newNode = new TrieNode(); p->next[c] = newNode; //链接结点 } p = p->next[c]; } p->value++; //用结点的特殊值来存储有多少个单词是在这结尾 } }Trie; typedef class AhoMachine{ public: Trie trie; int count; AhoMachine(){ trie = Trie(); count = 0; } void getFail(){ queue<TrieNode*> que; //以bfs序构造状态转移图 trie.root->fail = trie.root; for(int i = 0;i < SEG_SIZE;i++){ TrieNode* pNode = trie.root->next[i]; if(pNode != NULL){ que.push(pNode); pNode->fail = trie.root; //根节点的直接子节点的失配指针都是指向根节点 } } while(!que.empty()){ TrieNode* p = que.front(); que.pop(); for(int i = 0;i < SEG_SIZE;i++){ TrieNode* pNode = p->next[i]; if(pNode == NULL) continue; que.push(pNode); TrieNode* pFail = p->fail; //直到匹配,或者已经指向了根节点 while(pFail != trie.root && pFail->next[i] == NULL) pFail = pFail->fail; pNode->fail = pFail->next[i]; if(pNode->fail == NULL) pNode->fail = trie.root; //后缀链接的链接,指向失配后的结点或失配后的结点的后缀链接 pNode->last = (pNode->fail->value != 0)?(pNode->fail):(pNode->fail->last); } } } //当匹配完,或者是在一条链的中途仍然可能存在有匹配的结点 void rfind(TrieNode *p){ if(p != NULL){ count += p->value; rfind(p->last); p->value = 0; } } void find(string s){ TrieNode *pNode = trie.root; for(int i = 0;i < s.length();i++){ int c = Trie::cti(s[i]); while(pNode != trie.root && pNode->next[c] == NULL) pNode = pNode->fail; pNode = pNode->next[c]; if(pNode == NULL) pNode = trie.root; if(pNode->value != 0) rfind(pNode); //判断有没有可能匹配完其它的模板 else if(pNode->last != NULL) rfind(pNode->last); } } }AC; AC *ac; int cases; string buf; int n; int main(){ ios::sync_with_stdio(false); //取消同步,加快cin读取字符串的速度 cin>>cases; while(cases--){ ac = new AC(); cin>>n; for(int i = 0;i < n;i++){ cin>>buf; ac->trie.insert(buf); } cin>>buf; ac->getFail(); ac->find(buf); cout<<ac->count<<endl; delete ac; } return 0; }
[后记]
附上自己调程序时所用的数据生成器,如果用随机数生成可能基本上刷个1000,2000组很多问题都不能找出来,
因为直接用随机数要刷出点神数据的概率还是比较低的
#include<iostream> #include<fstream> #include<cstdio> #include<cstdlib> #include<ctime> #include<sstream> using namespace std; ofstream fout("ks.in"); //测试数据最少组数 #define CASE_LOW 3 //测试数据最大生成组数(CASE_LOW + CASE_LIMIT - 1) #define CASE_LIMIT 10 //关键字最小生成组数 #define KEYWORD_LOW 3 #define KEYWORD_LIMIT 10 #define KEYWORD_MAX_LEN 5 //生成文章的次数 #define STR_TIMES 10 #define SUBSTR_LEN 5 string buf[KEYWORD_LIMIT + KEYWORD_LOW]; string str; int _count; string operator +(string str, char c){ stringstream ss; ss<<str<<c; return ss.str(); } int main(){ srand((unsigned)time(NULL)); int cases = rand()%CASE_LIMIT + CASE_LOW; fout<<cases<<endl; for(int i = 0;i < cases;i++){ _count = rand()%KEYWORD_LIMIT + KEYWORD_LOW; fout<<_count<<endl; for(int j = 1; j <= _count;j++){ int len = rand()%KEYWORD_MAX_LEN + 1; buf[j] = ""; for(int k = 1; k <= len;k++){ buf[j] = buf[j] + (char)(rand()%26 + 'a'); } fout<<buf[j]<<endl; } int times = rand()%STR_TIMES + 1; str = ""; for(int j = 0;j <= times;j++){ int v = rand()%3; if(v == 0){ str += buf[rand()%_count + 1]; }else{ int len = rand()%SUBSTR_LEN + 1; for(int i = 1;i <= len;i++){ str = str + (char)(rand()%26 + 'a'); } } } fout<<str<<endl; } fout.close(); return 0; }
md_ks.cpp
相关文章推荐
- 高可用集群技术之heartbeat应用案例详解(二)
- View的滑动冲突(通用解决方式)
- idea 使用注意
- linux中动态库和静态库
- spring整合hibernate扫描多个不同包下的实体类
- 重学 以太网的mac协议的CSMA/CD
- hdu 5752 Sqrt Bo 水题
- Object中的finalize方法的使用
- Android for arm上的so注入(inject)和挂钩(hook)
- 对象序列化
- 提高Linux工作效率的十大bash技巧
- nginx用户认证
- 微信的redirect_uri参数错误解决办法
- 我与IDEA的不舍情缘
- 利用red5搭建一个简单的流媒体直播系统(ubuntu 12.10)
- java过滤敏感词实现字符串替换功能
- 面试准备之---排序
- 简单的tab切换(jquery)
- css重置
- 轻松搞定JSONP跨域请求