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自动机入门经典题目(两种表达方式)的更多相关文章

  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. 2019 快乐阳光java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.快乐阳光等公司offer,岗位是Java后端开发,最终选择去了快乐阳光. 面试了很多家公司,感觉大部分公司考察的点 ...

  2. Spring Security 解析(一) —— 授权过程

    Spring Security 解析(一) -- 授权过程   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .S ...

  3. Git查看文件制定行区间的提交记录

    git blame -L , /dir/file/file.php 这里查看file文件下6610至6613行的修改记录

  4. token jwt配置

    1. token jwt配置 1.1. pom <!-- token验证 --> <dependency> <groupId>io.jsonwebtoken< ...

  5. JAVA基础之HttpServletRequest请求

    HttpServletRequest请求是获取请求行.请求头和请求体:可以通过这个方法设置防盗链,获取地址.牢记解决乱码的方式. 怎么选择是重定向还是转发呢?通常情况下转发更快,而且能保持reques ...

  6. Firebird 事务隔离级别

    各种RDBMS事务隔离都差不多,Firebird 中大致分为3类: CONCURRENCY.READ_COMMITTED.CONSISTENCY. 在提供的数据库驱动里可设置的事务隔离级别大致如下3类 ...

  7. Java 单例类

    单例类:该类只能创建一个实例,或者说内存中只有一个实例,该类的对象引用的都是这个实例. 示例: package my_package; //定义一个单例类 class Singleton{ //使用一 ...

  8. 一行Python代码画心型

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/yanlaifan/article/deta ...

  9. 申请软件著作权,wps显示代码行号功能

    申请软件著作权时,要提交代码. 格式要求,每页不少于50行,怎么设置格式,保障每页至少50行呢? 选择[页面布局]---[行号]--[每页重编行号]即可显示出来,根据显示出来的行号,调整行距等格式即可 ...

  10. 监控服务zabbix部署

    目录 1. zabbix介绍 2. zabbix特点 3. zabbix配置文件 4. 部署zabbix 4.1 zabbix服务端安装 4.2 zabbix服务端配置 4.3 zabbix服务端we ...