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也就是"广播接收者"的意思,顾名思义,它就是用来 ...
随机推荐
- WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码
原文:WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码 HLSL,High Level Shader Language,高级着色器语言,是 Di ...
- EFCore自动迁移
2019/05/14,EFCore 2.2.4 有两种方式: 使用Migrate()方法 if (DbContext.Database.GetPendingMigrations().Any()) { ...
- 关于.Net使用企业库访问MySql数据库
关于.Net使用企业库访问MySql数据库 在网上看了很多又重写又加WebConfig中的内容,其实不用那么麻烦 企业库5.0访问MySql数据库只需要在Web服务器安装mysql-connector ...
- np.minimum()与tf.minimum()的用法
总结:二者用法一致.a=np.array([[[[10,8,3,9],[5,6,7,8]]],[[[1,2,3,4],[5,6,7,8]]],[[[1,2,3,4],[5,6,7,8]]]] )pri ...
- 2019 汇量科技java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.汇量科技等公司offer,岗位是Java后端开发,因为发展原因最终选择去了汇量科技,入职一年时间了,也成为了面 ...
- react新旧生命周期
React16.3.0之前生命周期 16.3开始建议使用新的生命周期
- 在eclipse下给android应用添加jar包
右键工程,Build path,java build path,选择libraries在右边的按钮中点击“Add Library”选择“User library”,点击“下一步”点击“User lib ...
- 约束布局ConstraintLayout
Android新特性介绍,ConstraintLayout完全解析 约束布局ConstraintLayout用法全解析 约束布局ConstraintLayout看这一篇就够了
- Oracle 数据块
以emp表为例 SYS@ prod>select * from scott.emp; EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO --------- ...
- sklearn.feature_extraction.text 的TfidfVectorizer函数
TfidfVectorizer函数主要用于,将文档(句子)等通过 tf-idf值来进行表示,也就是用一个tf-idf值的矩阵来表示文档(句子也可). from sklearn.feature_extr ...