Time Limit: 1000MS   Memory Limit: 131072KB   64bit IO Format: %I64d & %I64u

Submit Status

Description

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. 
 

Input

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. 
 

Output

Print how many keywords are contained in the description.
 

Sample Input

1
5
she
he
say
shr
her
yasherhs
 

Sample Output

3
 ——————————————————————————————————————————————————————————————————————————————————
题目大意:
给定n个子串和一个主串,求有多少个子串在主串中出现过。
(下面的介绍很错略,可参考:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html,本人大多数代码接参考于上面的博客。)
题目解法:AC自动机。
AC自动机,据说是1975年产生自贝尔实验室。多模式匹配算法。
知识储备:trie树、KMP算法思想
操作主要分为三步:
一:建立字典树(trie)。
把n个子串构建字典树,节点需要增加一个变量node * fail,即失败指针。
 1 struct node
2 {
3 node * fail;
4 node * next[kind];
5 int count;
6 node ()
7 {
8 fail=NULL;
9 memset(next,NULL,sizeof(next));
10 count=0;
11 }
12 };

二:建立失败指针。

失败指针分为三类:

1、root的失败指针指向NULL

2、root孩子的失败指针指向root

3、其余节点的失败指针按照以下方法:沿该节点的父亲节点的失败指针查找同样有该节点的节点,把该节点的失败指针指向那个节点的该节点。如果找不到则指向root。如:该节点(1)为‘a',而该节点的父亲节点(2)为’c',则查找'c'的失败指针指向的节点(3),当然节点(3)也为’c',如果节点(3)有’a'这个孩子(节点(4)),则把节点(1)的失败指针指向节点(4),如果节点(3)没有‘a'这个孩子,则沿着沿的失败指针继续查找,直到NULL。则把失败指针指向root。

建立的方法:

由于1、2类节点的失败指针一定,而第3指针是沿着父亲的失败指针查找,所以用队列维护指针。

 1 void buildac(node * root)
2 {
3 int i;
4 root->fail=NULL;
5 q.push(root);
6 while(!q.empty())
7 {
8 node *tp=q.front(),*p;
9 q.pop();
10 for(int i=0;i<26;i++)
11 {
12 if(tp->next[i]!=NULL)
13 {
14 if(tp==root)tp->next[i]->fail=root;
15 else
16 {
17 p=tp->fail;
18 while(p!=NULL)
19 {
20 if(p->next[i]!=NULL)
21 {
22 tp->next[i]->fail=p->next[i];
23 break;
24 }
25 p=p->fail;
26 }
27 if(p==NULL)tp->next[i]->fail=root;
28 }
29 q.push(tp->next[i]);
30 }
31 }
32 }
33 }

三、查询。

查询方法:指针p指向root,沿着主串的字母走,如果该节点没法走则跳到失败指针再走,如果还不能走则再跳直到到达root。如果某一个点匹配成功则沿失败指针统计对应失败指针的count。

int query(node *root)
{
int i=0,cnt=0,index;
node *p=root;
while(s[i])
{
index=s[i]-'a';
while(p->next[index]==NULL && p!=root)p=p->fail;
p=(p->next[index]==NULL)?root:p->next[index];
node *tp=p;
while(tp!=root && tp->count!=-1)
{
cnt+=tp->count;
tp->count=-1;
tp=tp->fail;
}
i++;
}
return cnt;
}
——————————————————————————————————————————————————————————————————————————————————
  1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4
5 using namespace std;
6 const int kind=26;
7 struct node
8 {
9 node * fail;
10 node * next[kind];
11 int count;
12 node ()
13 {
14 fail=NULL;
15 memset(next,NULL,sizeof(next));
16 count=0;
17 }
18 };
19 typedef node * np;
20 queue<np>q;
21 char keyw[52],s[1000010];
22 node * root=NULL;
23 int t,n;
24 void ins(char s[],node *root)
25 {
26 node *p=root;
27 int i=0,index;
28 while(s[i])
29 {
30 index=s[i]-'a';
31 if(!p->next[index])p->next[index]=new node;
32 p=p->next[index];
33 i++;
34 }
35 p->count++;
36 }
37 void buildac(node * root)
38 {
39 int i;
40 root->fail=NULL;
41 q.push(root);
42 while(!q.empty())
43 {
44 node *tp=q.front(),*p;
45 q.pop();
46 for(int i=0;i<26;i++)
47 {
48 if(tp->next[i]!=NULL)
49 {
50 if(tp==root)tp->next[i]->fail=root;
51 else
52 {
53 p=tp->fail;
54 while(p!=NULL)
55 {
56 if(p->next[i]!=NULL)
57 {
58 tp->next[i]->fail=p->next[i];
59 break;
60 }
61 p=p->fail;
62 }
63 if(p==NULL)tp->next[i]->fail=root;
64 }
65 q.push(tp->next[i]);
66 }
67 }
68 }
69 }
70
71 int query(node *root)
72 {
73 int i=0,cnt=0,index;
74 node *p=root;
75 while(s[i])
76 {
77 index=s[i]-'a';
78 while(p->next[index]==NULL && p!=root)p=p->fail;
79 p=p->next[index];
80 p=(p==NULL)?root:p;
81 node *tp=p;
82 while(tp!=root && tp->count!=-1)
83 {
84 cnt+=tp->count;
85 tp->count=-1;
86 tp=tp->fail;
87 }
88 i++;
89 }
90 return cnt;
91 }
92 int main()
93 {
94 scanf("%d",&t);
95 while(t--)
96 {
97 root=new node;
98 scanf("%d",&n);
99 while(n--)
100 {
101 scanf("%s",keyw);
102 ins(keyw,root);
103 }
104 buildac(root);
105 scanf("%s",s);
106 printf("%d\n",query(root));
107 }
108 return 0;
109 }

HDU2222 Keywords Search__AC自动机的更多相关文章

  1. HDU2222 Keywords Search 【AC自动机】

    HDU2222 Keywords Search Problem Description In the modern time, Search engine came into the life of ...

  2. hdu2222 Keywords Search ac自动机

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=2222 题目: Keywords Search Time Limit: 2000/1000 MS ...

  3. HDU2222 Keywords Search [AC自动机模板]

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  4. HDU2222 Keywords Search(AC自动机)

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  5. hdu2222 Keywords Search【AC自动机】

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  6. 【AC自动机】hdu2222 Keywords Search

    AC自动机模板题,给你n个模式串和一个文本串,问你有几个模式串在文本串出现过. 注意防止重复统计 这里推荐一波郭大爷的介绍,简单易懂. http://www.bilibili.com/video/av ...

  7. HDU2222 Keywords Search —— AC自动机

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 Keywords Search Time Limit: 2000/1000 MS (Java/O ...

  8. AC自动机讲解+[HDU2222]:Keywords Search(AC自动机)

    首先,有这样一道题: 给你一个单词W和一个文章T,问W在T中出现了几次(原题见POJ3461). OK,so easy~ HASH or KMP 轻松解决. 那么还有一道例题: 给定n个长度不超过50 ...

  9. HDU-2222 Keywords Search 字符串问题 AC自动机

    题目链接:https://cn.vjudge.net/problem/HDU-2222 题意 给一些关键词,和一个待查询的字符串 问这个字符串里包含多少种关键词 思路 AC自动机模版题咯 注意一般情况 ...

随机推荐

  1. Mysql 8.0 相关命令

    1.dos窗口命令登陆. 管理员/普通用户登陆(账号/密码:root/rootpwd) mysql -hlocalhost -uroot -prootpwd 普通用户登陆(root管理员的不可以使用这 ...

  2. 如何解决Renesas USB3.0RootHub警告

    打开WINDOWS系统的[计算机管理]-[服务和应用程序]-[服务]-点击[Portable Device Enumerator Service]服务,设置为启动类型:自动(延迟启动).并点击&quo ...

  3. Spring—SSJ集成&声明式事务管理

    1.   课程介绍 1.  SSJ集成;(掌握) 2.  声明式事务管理;(掌握) 什么是三大框架 2.1.  ssh Struts/Struts2 Spring Hibernate 2.2.  ss ...

  4. erlang开发环境(IDE)搭建

    1.首先推荐:intellij idea http://www.open-open.com/news/view/44c90e 2.webstorm: http://plugins.jetbrains. ...

  5. 如何解决Visual Studio 首次调试 docker 的 vs2017u5 exists, deleting Opening stream failed, trying again with proxy settings

    前言 因为之前我电脑安装的是windows10家庭版,然而windows10家庭没有Hyper-v功能. 搜索了几篇windows10家庭版安装docker相关的博客,了解一些前辈们走过的坑. 很多人 ...

  6. 每日一个linux命令6 -- rmdir

    rmdir doc 如果doc为空目录则删除,否则无法删除. rmdir -p test2/test3 递归删除空目录,首先判断test3,如果test3为空,则删除test3,此时判断test2,如 ...

  7. UML第三次结对作业

    这个作业要求在哪里 https://edu.cnblogs.com/campus/fzzcxy/2018SE1/homework/11274 这个作业的目标 <学会使用专业的建模工具> 队 ...

  8. 解放双手,markdown文章神器,Typora+PicGo+七牛云图床实现自动上传图片

    本文主要分享使用Typora作为Markdown编辑器,PicGo为上传图片工具,使用七牛云做存储来解放双手实现图片的自动化上传与管理.提高写作效率,提升逼格.用过 Markdown 的朋友一定会深深 ...

  9. Linux下安装svn教程

    前言 最近买了新服务器,准备开始弄一些个人的开源项目.有了服务器当然是搞一波svn啦.方便自己的资料上传和下载.于是在此记录搭建svn的方式,方便以后直接使用. 安装 使用yum源进行安装,十分的方便 ...

  10. ReentrantLock-源码解析

    ReentrantLock类注释 1.可重入互斥锁,意思是表示该锁能够支持一个线程对资源的重复加锁,该锁还支持获取锁的公平和非公平性选择.synchronized关键字隐式的支持重进入. 2.可以通过 ...