AC自动机入门经典题目(两种表达方式)
Keywords Search
指针方式:
- /* Keywords Search */
- # include <iostream>
- # include <stdio.h>
- # include <string.h>
- # include <string>
- # include <cstdlib>
- # include <ctime>
- # include <cmath>
- # include <cctype>
- # include <vector>
- # include <deque>
- # include <queue>
- # include <stack>
- # include <climits>
- # include <bitset>
- # include <set>
- # include <map>
- using namespace std;
- # define N
- # define INF 0x3f3f3f3f
- # define lowbit(x)(x&(-x))
- struct node
- {
- int cnt;
- node *next[];
- node *fail;
- node(){
- cnt=;
- fail=NULL;
- memset(next, NULL, sizeof(next));
- }
- };
- node *root;
- char s[], str[N];
- int n;
- void init()
- {
- root = new node;
- }
- void _Insert(char *ss)
- {
- int len = strlen(ss);
- node *p=root;
- for(int i=; i<len; i++ )
- {
- int t=ss[i]-'a';
- if( p->next[t]==NULL )
- p->next[t]=new node;
- p=p->next[t];
- }
- p->cnt++;
- }
- void Build_the_fail()
- {
- root -> fail = NULL;
- //node *p=root;
- queue<node*>q;
- q.push(root);
- while( !q.empty() )
- {
- node *cur=q.front();
- q.pop();
- for(int i=; i<; i++ )
- {
- if( cur->next[i]!=NULL )
- {
- if( cur==root )
- cur->next[i]->fail = root;
- else
- {
- node *p=cur->fail;
- while( p!=NULL )
- {
- if( p->next[i]!=NULL )
- {
- cur->next[i]->fail = p->next[i];
- break;
- }
- else
- {
- p = p -> fail;
- }
- }
- if( p==NULL )
- cur->next[i]->fail = root;
- }
- q.push(cur->next[i]);
- }
- }
- }
- }
- int query(char *str)
- {
- node *cur=root;
- int pos;
- int cont=;
- int len=strlen(str);
- for(int i=; i<len; i++ )
- {
- pos=str[i]-'a';
- while( cur->next[pos]==NULL && cur!=root )
- {
- cur = cur->fail;
- }
- cur = cur->next[pos];
- if( cur==NULL )
- cur = root;
- node *temp=cur;
- while( temp!=root )
- {
- if( temp->cnt!=- )
- {
- cont += temp-> cnt;
- temp -> cnt = -;
- }
- temp = temp -> fail;
- }
- }
- return cont;
- }
- int main()
- {
- int t;
- scanf("%d", &t);
- while( t-- )
- {
- init();
- scanf("%d", &n);
- for(int i=; i<n; i++ )
- {
- scanf("%s", s);
- _Insert(s);
- }
- Build_the_fail();
- scanf("%s", str);
- printf("%d\n", query(str));
- }
- return ;
- }
数组方式:
- /* */
- # include <iostream>
- # include <algorithm>
- # include <utility>
- # include <memory>
- # include <deque>
- # include <queue>
- # include <stack>
- # include <map>
- # include <set>
- # include <list>
- # include <vector>
- # include <cassert>
- # include <functional>
- # include <bitset>
- # include <cmath>
- # include <cstdlib>
- # include <climits>
- # include <cstring>
- # include <string>
- using namespace std;
- typedef long long ll;
- # define mem(a,b)(a,b,sizeof(a))
- # define lowbit(x)(x&(-x))
- # define lcm(a,b)(a*b/__gcd(a,b))
- const ll mod=1e9+;
- const int maxn=;
- const double pi=acos(-1.0);
- struct ac_auto
- {
- int Next[maxn][], Fail[maxn], End[maxn];//Next[now][buf[i]-'a'] 是now节点存着buf[i]字符的子节点的编号
- int L, root;//注意这是全局变量,L是编号,root是根节点
- int newNode(){
- for(int i=; i<; i++ )//26叉树
- Next[L][i] = -;
- End[L++] = ;
- return L-;//返回节点编号
- }
- void Initial(){
- L=;
- root = newNode();
- }
- void Insert( char buf[] )
- {
- int len=strlen(buf);
- int now = root;
- for(int i=; i<len; i++ )
- {
- if( Next[now][buf[i]-'a'] == - )
- Next[now][buf[i]-'a'] = newNode();//若子节点没有buf[i],则插入buf[i]
- now = Next[now][buf[i]-'a'];//now是当前节点编号
- }
- End[now]++;//作为结束字符的编号+1,计算单词出现的次数
- }
- void Build_the_fail()
- {
- queue<int>ans;
- Fail[root] = root;//根节点的失败指针指向自己
- for(int i=; i<; i++ )
- {
- if( Next[root][i]==- )
- Next[root][i] = root;
- else
- {
- Fail[Next[root][i]] = root;//根节点的子节点的失败指针指向根节点
- ans.push(Next[root][i]);
- }
- }
- while( !ans.empty() )
- {
- int now = ans.front();
- ans.pop();
- for(int i=; i<; i++)
- {
- if( Next[now][i]==- )
- Next[now][i] = Next[Fail[now]][i];//若buf[i]没有插入字典树,则将令其等于其父节点的失败指针指向的节点的子节点buf[i]字符所在的节点
- else
- {
- Fail[Next[now][i]] = Next[Fail[now]][i];//若buf[i]已经插入,其失败指针就指向其父节点的失败指针指向的节点的子节点buf[i]所在的节点
- ans.push(Next[now][i]);//
- }
- }
- }
- }
- int Query( char buf[] )
- {
- int now = root;//从根节点开始找,now初始化为root
- int res = ;//结果
- int len = strlen(buf);
- for(int i=; i<len; i++ )
- {
- now = Next[now][buf[i]-'a'];//当前节点的编号
- int temp = now;
- while( temp!=root )
- {
- res += End[temp];//只有找到单词最后一个字符所在位置End[temp]才会>0,否则为0,所以可以直接加
- End[temp] = ;//加完后置为0
- temp = Fail[temp];//拓展到失败指针指向的位置,继续找
- }
- }
- return res;
- }
- }AC;
- const int MAXN = ;
- int T, n;
- char buf[MAXN];
- int main()
- {
- ios::sync_with_stdio(false);
- cin>>T;
- while( T-- )
- {
- cin>>n;
- AC.Initial();
- for(int i=; i<n; i++ )
- {
- cin>>buf;
- AC.Insert(buf);
- }
- AC.Build_the_fail();
- cin>>buf;
- cout<<AC.Query(buf)<<endl;
- }
- return ;
- }
AC自动机入门经典题目(两种表达方式)的更多相关文章
- Assignment写作需要掌握的两种表达方式
在正式开始写Assignment之前都会进行文献检索和整理,选择适合Assignment选题的文献资料进行阅读和引用.对于文献中与自己的观点高度相关的参考资料要如何具体引用,而不造成抄袭或者增加文章的 ...
- layui中弹出层的两种表达方式
方式一: 定义js中定义html变量 方式二: 设置div :hidden:hidden 布局 数据表格自适应大小: 代码: <style> .btn-container { margin ...
- AC自动机入门
Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. KMP算法很好的解决了单模式匹配问题,如果有了字典树的基础,我们可以完美的结合二者解决多 ...
- hdu2222 KeyWords Search AC自动机入门题
/** 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222 题意:题意:给定N(N <= 10000)个长度不大于50的模式串,再给定一个长度为L ...
- JavaScript 函数的两种声明方式
1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...
- POJ 2299-Ultra-QuickSort-线段树的两种建树方式
此题有两种建树方式! Description In this problem, you have to analyze a particular sorting algorithm. The algo ...
- Spring的核心api和两种实例化方式
一.spring的核心api Spring有如下的核心api BeanFactory :这是一个工厂,用于生成任意bean.采取延迟加载,第一次getBean时才会初始化Bean Applicatio ...
- Web APi之认证(Authentication)两种实现方式【二】(十三)
前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底 ...
- Android中BroadcastReceiver的两种注册方式(静态和动态)详解
今天我们一起来探讨下安卓中BroadcastReceiver组件以及详细分析下它的两种注册方式. BroadcastReceiver也就是"广播接收者"的意思,顾名思义,它就是用来 ...
随机推荐
- Java中守护线程的总结
在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆: 只要当前JVM实例中尚存 ...
- spring Boot 学习(四、Spring Boot与任务)
一.异步任务 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在 处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用 多线程来完成此类任务,其实,在Spri ...
- Web漏洞扫描
SkipFish skipfish语法格式,其他参数使用skipfish -h查看文档 skipfish -o skfish http://url/ -C 指定Cookie 最终会在~/root下面生 ...
- 重启Kubernetes Pod的几种方式
方法1 kubectl scale deployment XXXX --replicas=0 -n {namespace} kubectl scale deployment XXXX --replic ...
- 【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 前言部分 ...
- 0x01 Python logging模块
目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...
- web之表单form
表单是我们平常编写Web应用常用的工具,表单(<form>)用来收集用户提交的数据,发送到服务器.比如,用户提交用户名和密码,让服务器验证,就要通过表单.表单是一个包含表单元素或控件的区域 ...
- linux设备驱动程序--串行通信驱动框架分析
linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...
- Python入门篇-内建函数
Python入门篇-内建函数 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.常见的内建函数案例 1>.标识id 返回对象的唯一标识,CPython返回内存地址. #!/ ...
- Visual Studio Code 写Python代码
之前用nodepad++,sublime text3,ultraedit,最近上手微软的vsc感觉上手还行,如果没有pycharm照样可以使用它 https://code.visualstudio.c ...