hdu 1277 全文检索 (直接映射查找 || 自动机)
无聊做水题的时候发现的一道题目。这道题第一反应可以用自动机来解决。当然,条件是各种限制,从而导致可以用直接映射标记的方法来搜索。具体的做法就像RK算法一样,将字符串hash成一个数,这里每一个关键字前四位都是不同的,这样就有利于hash搜索了。当前四位匹配的时候,就可以搜索整个串是否完全匹配。这整个的复杂度大概是O(n*m),n是全文测长度,m是关键字的长度。
自动机代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <set> using namespace std; const int kind = ;
struct Node {
Node *next[kind];
Node *fail;
string label;
Node() {
memset(next, , sizeof(next));
fail = NULL;
label = "";
}
Node(char *tmp) {
memset(next, , sizeof(next));
fail = NULL;
label = tmp;
}
} ; struct Trie {
Node *Root;
Trie() { Root = new Node();} void insert(char *s, char *label) {
Node *p = Root;
while (*s) {
int idx = *s - '';
if (!p->next[idx]) {
p->next[idx] = new Node();
p->next[idx]->fail = p;
}
p = p->next[idx];
s++;
}
p->label = label;
}
void build() {
queue<Node *> Q;
while (!Q.empty()) Q.pop();
Q.push(Root);
Root->fail = NULL;
Node *cur, *p;
while (!Q.empty()) {
cur = Q.front();
Q.pop();
for (int i = ; i < kind; i++) {
// cout << cur->next[i] << ' ';
if (cur->next[i]) {
// cout << i << ' ';
Q.push(cur->next[i]);
p = cur->fail;
while (p) {
if (p->next[i]) {
cur->next[i]->fail = p->next[i];
break;
}
p = p->fail;
}
if (!p) cur->next[i]->fail = Root;
}
}
}
}
void query(char *s) {
set<string> vis;
bool pnt = false;
Node *cur = Root;
while (*s) {
int idx = *(s++) - '';
while (cur && !cur->next[idx]) cur = cur->fail;
cur = cur ? cur->next[idx] : Root;
if (vis.find(cur->label) != vis.end()) continue;
if (cur->label.length()) {
if (!pnt) {
printf("Found key:");
pnt = true;
}
cout << ' ' << cur->label;
vis.insert(cur->label);
}
}
if (!pnt) puts("No key can be found !");
cout << endl;
}
} trie; char str[], buf[]; int main() {
// freopen("in", "r", stdin);
int n, m;
while (cin >> n >> m) {
trie = Trie();
gets(buf);
str[] = ;
while (n-- && gets(buf)) strcat(str, buf);
gets(buf);
while (m-- && gets(buf)) {
char *p = buf;
while (*(p++) != ']') ;
*(p++) = ;
while (*p == ' ') p++;
trie.insert(p, buf);
// cout << p << ' ' << buf << " inserted!"<< endl;
}
trie.build();
// cout << "built!!" << endl;
trie.query(str);
}
return ;
}
UPD:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string> using namespace std; const int HASHLEN = ;
const int M = ;
const int N = ;
string label[N], key[N];
bool vis[N];
int id[M];
char str[ * N], buf[N]; bool check(int t, char *p) {
int len = key[t].length();
for (int i = ; i < len; i++) {
if (key[t][i] != p[i]) return false;
}
return true;
} void work(char *p) {
bool pnt = false;
char *q = p;
int cur = , ep = ;
for (int i = ; i < HASHLEN - ; i++) cur = cur * + *(q++) - '', ep *= ;
while (*q && *p) {
// cout << cur << endl;
cur = cur * + *q - '';
cur %= ep;
int t = id[cur];
if (t != - && !vis[t]) {
if (check(t, p)) {
if (!pnt) printf("Found key:");
pnt = vis[t] = true;
cout << ' ' << label[t];
}
}
p++, q++;
}
if (!pnt) printf("No key can be found !");
cout << endl;
} int main() {
// freopen("in", "r", stdin);
int n, m;
while (cin >> n >> m) {
memset(id, -, sizeof(id));
memset(vis, , sizeof(vis));
gets(buf);
str[] = ;
while (n-- && gets(buf)) strcat(str, buf);
gets(buf);
for (int i = ; i < m; i++) {
gets(buf);
char *p = buf;
while (*p && *p != ']') p++;
*(++p) = ;
p++;
while (*p && *p == ' ') p++;
label[i] = buf;
key[i] = p;
// cout << label[i] << ' ' << key[i] << endl;
int cid = ;
for (int i = ; i < HASHLEN; i++) cid = cid * + p[i] - '';
// cout << cid << endl;
if (id[cid] != -) { puts("shit!"); while () ;}
id[cid] = i;
}
work(str);
}
return ;
}
不知道为什么这个代码能过G++但是C++过不了,应该是代码里面有bug。另外,数据似乎跟描述的有点出入,说好的不同key值的前四位不会相同,可是写了句来试它的数据时就发现被骗了,所以后来用了5位,过了!
——written by Lyon
hdu 1277 全文检索 (直接映射查找 || 自动机)的更多相关文章
- hdu 1277 全文检索
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1277 全文检索 Description 我们大家经常用google检索信息,但是检索信息的程序是很困难 ...
- HDU 1277全文检索(字典树)
全文检索 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- hdu 1277 全文检索 (字典树应用)
全文检索 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- hdu 2896 病毒侵袭 AC自动机(查找包含哪些子串)
病毒侵袭 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...
- hdu 2896 病毒侵袭 ac自动机
/* hdu 2896 病毒侵袭 ac自动机 从题意得知,模式串中没有重复的串出现,所以结构体中可以将last[](后缀链接)数组去掉 last[]数组主要是记录具有相同后缀模式串的末尾节点编号 .本 ...
- hdu 1277 AC自动机入门(指针版和数组版)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1277 推荐一篇博客(看思路就可以,实现用的是java): https://www.cnblogs.co ...
- hdu 1277 AC自动机
全文检索 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- HDU 5164Matching on Array(AC自动机)
这是BC上的一道题,当时比赛没有做,回头看看题解,说是AC自动机,想着没有写过AC自动机,于是便试着抄抄白书的模板,硬是搞了我数个小时2000ms时限1800过了= = ! 这里就直接贴上BC的结题报 ...
- hdu 2222 Keywords Search ac自动机入门
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:有N(N <= 10000)个长度不超过50的模式串和一个长度不超过1e6的文本串. ...
随机推荐
- 二零一七年工作中常用的基本Linux命令记录(Ubuntu)
Linux命令如下(Ubuntu): 1. apt-get install openssh-server 下载远程工具 2. apt-get install lrzsz 上传下载工具 3. apt-g ...
- python 常见分布的产生方式
- 【洛谷】 P1420 最长连号
题目描述 输入n个正整数,(1<=n<=10000),要求输出最长的连号的长度.(连号指从小到大连续自然数) 输入输出格式 输入格式: 第一行,一个数n; 第二行,n个正整数,之间用空格隔 ...
- 【CODEVS】2618 核电站问题
2618 核电站问题 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 一个核电站有N个放核物质的坑,坑排列在一条直 ...
- 模拟7题解 T1方程的解
方程的解 [扩展欧几里德] 首先进行特判,两个小时基本想到了,除了a!=0,b==0,a*c<0这种情况 其次就是一般情况: 首先exgcd求出ax+by=GCD(a,b)的一组任意解 然后两边 ...
- 实践中了解到的CSS样式的优先级
CSS三大特性——继承.优先级和层叠.这是在精通CSS中重点强调的内容. 继承即子类元素继承父类的样式,常用的可继承样式有:color,font,line-height,list-style,text ...
- 可复用且高度解耦的iOS用户统计实现
http://www.cocoachina.com/ios/20160421/15912.html 本文为投稿文章,作者:编程小翁(简书) 用户统计 用户行为统计(User Behavior Stat ...
- 移动端的touch事件(一)
如果我们允许用户在页面上用类似桌面浏览器鼠标手势的方式来控制WEB APP,这个页面上肯定是有很多可点击区域的,如果用户触摸到了那些可点击区域怎么办呢?? 诸如智能手机和平板电脑一类的移动设备通常会有 ...
- ThinkPHP中_after_update、_before_update等的用法
https://blog.csdn.net/aslackers/article/details/50339163 TP系统\Think\Model类里隐藏了几个有用的方法: _before_inser ...
- Sum Root to Leaf Numbers深度优先计算路径和
Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...