Keywords Search

指针方式:

  1. /* Keywords Search */
  2. # include <iostream>
  3. # include <stdio.h>
  4. # include <string.h>
  5. # include <string>
  6. # include <cstdlib>
  7. # include <ctime>
  8. # include <cmath>
  9. # include <cctype>
  10. # include <vector>
  11. # include <deque>
  12. # include <queue>
  13. # include <stack>
  14. # include <climits>
  15. # include <bitset>
  16. # include <set>
  17. # include <map>
  18. using namespace std;
  19.  
  20. # define N
  21. # define INF 0x3f3f3f3f
  22. # define lowbit(x)(x&(-x))
  23.  
  24. struct node
  25. {
  26. int cnt;
  27. node *next[];
  28. node *fail;
  29. node(){
  30. cnt=;
  31. fail=NULL;
  32. memset(next, NULL, sizeof(next));
  33. }
  34. };
  35. node *root;
  36. char s[], str[N];
  37. int n;
  38.  
  39. void init()
  40. {
  41. root = new node;
  42. }
  43.  
  44. void _Insert(char *ss)
  45. {
  46. int len = strlen(ss);
  47. node *p=root;
  48. for(int i=; i<len; i++ )
  49. {
  50. int t=ss[i]-'a';
  51. if( p->next[t]==NULL )
  52. p->next[t]=new node;
  53. p=p->next[t];
  54. }
  55. p->cnt++;
  56. }
  57.  
  58. void Build_the_fail()
  59. {
  60. root -> fail = NULL;
  61. //node *p=root;
  62. queue<node*>q;
  63. q.push(root);
  64.  
  65. while( !q.empty() )
  66. {
  67. node *cur=q.front();
  68. q.pop();
  69.  
  70. for(int i=; i<; i++ )
  71. {
  72. if( cur->next[i]!=NULL )
  73. {
  74. if( cur==root )
  75. cur->next[i]->fail = root;
  76. else
  77. {
  78. node *p=cur->fail;
  79. while( p!=NULL )
  80. {
  81. if( p->next[i]!=NULL )
  82. {
  83. cur->next[i]->fail = p->next[i];
  84. break;
  85. }
  86.  
  87. else
  88. {
  89. p = p -> fail;
  90. }
  91. }
  92. if( p==NULL )
  93. cur->next[i]->fail = root;
  94. }
  95. q.push(cur->next[i]);
  96. }
  97. }
  98. }
  99. }
  100.  
  101. int query(char *str)
  102. {
  103. node *cur=root;
  104. int pos;
  105. int cont=;
  106. int len=strlen(str);
  107. for(int i=; i<len; i++ )
  108. {
  109. pos=str[i]-'a';
  110. while( cur->next[pos]==NULL && cur!=root )
  111. {
  112. cur = cur->fail;
  113. }
  114. cur = cur->next[pos];
  115. if( cur==NULL )
  116. cur = root;
  117. node *temp=cur;
  118. while( temp!=root )
  119. {
  120. if( temp->cnt!=- )
  121. {
  122. cont += temp-> cnt;
  123. temp -> cnt = -;
  124. }
  125. temp = temp -> fail;
  126. }
  127. }
  128. return cont;
  129. }
  130.  
  131. int main()
  132. {
  133. int t;
  134. scanf("%d", &t);
  135. while( t-- )
  136. {
  137. init();
  138. scanf("%d", &n);
  139. for(int i=; i<n; i++ )
  140. {
  141. scanf("%s", s);
  142. _Insert(s);
  143. }
  144. Build_the_fail();
  145. scanf("%s", str);
  146. printf("%d\n", query(str));
  147. }
  148. return ;
  149. }

数组方式:

  1. /* */
  2. # include <iostream>
  3. # include <algorithm>
  4. # include <utility>
  5. # include <memory>
  6. # include <deque>
  7. # include <queue>
  8. # include <stack>
  9. # include <map>
  10. # include <set>
  11. # include <list>
  12. # include <vector>
  13. # include <cassert>
  14. # include <functional>
  15. # include <bitset>
  16. # include <cmath>
  17. # include <cstdlib>
  18. # include <climits>
  19. # include <cstring>
  20. # include <string>
  21. using namespace std;
  22. typedef long long ll;
  23.  
  24. # define mem(a,b)(a,b,sizeof(a))
  25. # define lowbit(x)(x&(-x))
  26. # define lcm(a,b)(a*b/__gcd(a,b))
  27. const ll mod=1e9+;
  28. const int maxn=;
  29. const double pi=acos(-1.0);
  30.  
  31. struct ac_auto
  32. {
  33. int Next[maxn][], Fail[maxn], End[maxn];//Next[now][buf[i]-'a'] 是now节点存着buf[i]字符的子节点的编号
  34. int L, root;//注意这是全局变量,L是编号,root是根节点
  35.  
  36. int newNode(){
  37. for(int i=; i<; i++ )//26叉树
  38. Next[L][i] = -;
  39. End[L++] = ;
  40. return L-;//返回节点编号
  41. }
  42.  
  43. void Initial(){
  44. L=;
  45. root = newNode();
  46. }
  47.  
  48. void Insert( char buf[] )
  49. {
  50. int len=strlen(buf);
  51. int now = root;
  52. for(int i=; i<len; i++ )
  53. {
  54. if( Next[now][buf[i]-'a'] == - )
  55. Next[now][buf[i]-'a'] = newNode();//若子节点没有buf[i],则插入buf[i]
  56. now = Next[now][buf[i]-'a'];//now是当前节点编号
  57. }
  58. End[now]++;//作为结束字符的编号+1,计算单词出现的次数
  59. }
  60.  
  61. void Build_the_fail()
  62. {
  63. queue<int>ans;
  64. Fail[root] = root;//根节点的失败指针指向自己
  65.  
  66. for(int i=; i<; i++ )
  67. {
  68. if( Next[root][i]==- )
  69. Next[root][i] = root;
  70. else
  71. {
  72. Fail[Next[root][i]] = root;//根节点的子节点的失败指针指向根节点
  73. ans.push(Next[root][i]);
  74. }
  75. }
  76.  
  77. while( !ans.empty() )
  78. {
  79. int now = ans.front();
  80. ans.pop();
  81.  
  82. for(int i=; i<; i++)
  83. {
  84. if( Next[now][i]==- )
  85. Next[now][i] = Next[Fail[now]][i];//若buf[i]没有插入字典树,则将令其等于其父节点的失败指针指向的节点的子节点buf[i]字符所在的节点
  86. else
  87. {
  88. Fail[Next[now][i]] = Next[Fail[now]][i];//若buf[i]已经插入,其失败指针就指向其父节点的失败指针指向的节点的子节点buf[i]所在的节点
  89. ans.push(Next[now][i]);//
  90. }
  91. }
  92. }
  93. }
  94.  
  95. int Query( char buf[] )
  96. {
  97. int now = root;//从根节点开始找,now初始化为root
  98. int res = ;//结果
  99. int len = strlen(buf);
  100.  
  101. for(int i=; i<len; i++ )
  102. {
  103. now = Next[now][buf[i]-'a'];//当前节点的编号
  104. int temp = now;
  105. while( temp!=root )
  106. {
  107. res += End[temp];//只有找到单词最后一个字符所在位置End[temp]才会>0,否则为0,所以可以直接加
  108. End[temp] = ;//加完后置为0
  109. temp = Fail[temp];//拓展到失败指针指向的位置,继续找
  110. }
  111. }
  112. return res;
  113. }
  114. }AC;
  115.  
  116. const int MAXN = ;
  117. int T, n;
  118. char buf[MAXN];
  119.  
  120. int main()
  121. {
  122. ios::sync_with_stdio(false);
  123. cin>>T;
  124. while( T-- )
  125. {
  126. cin>>n;
  127. AC.Initial();
  128. for(int i=; i<n; i++ )
  129. {
  130. cin>>buf;
  131. AC.Insert(buf);
  132. }
  133. AC.Build_the_fail();
  134. cin>>buf;
  135. cout<<AC.Query(buf)<<endl;
  136. }
  137. return ;
  138. }

AC自动机入门经典题目(两种表达方式)的更多相关文章

  1. Assignment写作需要掌握的两种表达方式

    在正式开始写Assignment之前都会进行文献检索和整理,选择适合Assignment选题的文献资料进行阅读和引用.对于文献中与自己的观点高度相关的参考资料要如何具体引用,而不造成抄袭或者增加文章的 ...

  2. layui中弹出层的两种表达方式

    方式一: 定义js中定义html变量 方式二: 设置div :hidden:hidden 布局 数据表格自适应大小: 代码: <style> .btn-container { margin ...

  3. AC自动机入门

    Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. KMP算法很好的解决了单模式匹配问题,如果有了字典树的基础,我们可以完美的结合二者解决多 ...

  4. hdu2222 KeyWords Search AC自动机入门题

    /** 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:题意:给定N(N <= 10000)个长度不大于50的模式串,再给定一个长度为L ...

  5. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

  6. POJ 2299-Ultra-QuickSort-线段树的两种建树方式

    此题有两种建树方式! Description In this problem, you have to analyze a particular sorting algorithm. The algo ...

  7. Spring的核心api和两种实例化方式

    一.spring的核心api Spring有如下的核心api BeanFactory :这是一个工厂,用于生成任意bean.采取延迟加载,第一次getBean时才会初始化Bean Applicatio ...

  8. Web APi之认证(Authentication)两种实现方式【二】(十三)

    前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...

  9. Android中BroadcastReceiver的两种注册方式(静态和动态)详解

    今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...

随机推荐

  1. Java中守护线程的总结

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆: 只要当前JVM实例中尚存 ...

  2. spring Boot 学习(四、Spring Boot与任务)

    一.异步任务 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在 处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用 多线程来完成此类任务,其实,在Spri ...

  3. Web漏洞扫描

    SkipFish skipfish语法格式,其他参数使用skipfish -h查看文档 skipfish -o skfish http://url/ -C 指定Cookie 最终会在~/root下面生 ...

  4. 重启Kubernetes Pod的几种方式

    方法1 kubectl scale deployment XXXX --replicas=0 -n {namespace} kubectl scale deployment XXXX --replic ...

  5. 【AIX】3004-314 Password was recently used and is not valid for reuse

    [AIX]3004-314 Password was recently used and is not valid for reuse   一.1  BLOG文档结构图     一.2  前言部分   ...

  6. 0x01 Python logging模块

    目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...

  7. web之表单form

    表单是我们平常编写Web应用常用的工具,表单(<form>)用来收集用户提交的数据,发送到服务器.比如,用户提交用户名和密码,让服务器验证,就要通过表单.表单是一个包含表单元素或控件的区域 ...

  8. linux设备驱动程序--串行通信驱动框架分析

    linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...

  9. Python入门篇-内建函数

    Python入门篇-内建函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.常见的内建函数案例  1>.标识id 返回对象的唯一标识,CPython返回内存地址. #!/ ...

  10. Visual Studio Code 写Python代码

    之前用nodepad++,sublime text3,ultraedit,最近上手微软的vsc感觉上手还行,如果没有pycharm照样可以使用它 https://code.visualstudio.c ...