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. ASP.NET SignalR 系列(四)之指定对象推送

    在上一章讲到了广播推送,即所有订阅的用户都能收到,这种适合于信息广播. 接下来介绍如何给指定的对象推送 在讲这个之前先说明一下连接创建的基础知识 1.每个页面与服务端创建连接并启动时,这时服务端会产生 ...

  2. NEST 自定义分析器

    public void SetAnalysis() { if (!client.IndexExists("employee").Exists) { client.CreateInd ...

  3. 用jQuery的toggle方法实现元素的左右滑动隐藏

    通常情况下给元素加toggle方法通常会是上下滑动隐藏,而有时我们又需要左右滑动隐藏怎么办呢 $(document).ready(function(){ $('#example').click(fun ...

  4. kali安装结束重启黑屏?

    很多人碰到过kali在安装结束后自动重启,屏幕黑屏就显示一个光标. 解决办法: 安装最后一步,不要选择默认项 Enter device manually 改选第二项.....具体什么忘记了. 即可解决 ...

  5. The Middle English word was Affrike非洲

    Africa (n.) Latin Africa (terra) "African land, Libya, the Carthaginian territory, the province ...

  6. linux技能点三 find grep

    find:      1.   按文件名查找    find . -name "a*.txt"     注意双引号:  2.   按文件大小查找 find .-size [+/-] ...

  7. angularcli 第六篇(todolist 列表)

    1.通过文本框输入,向数组添加数据 <!-- 通过文本框输入,向数组添加数据 push --> <input type="text" name="111 ...

  8. configure生成makefile的配置项说明

    一般Linux软件使用configure来检测系统生成makefile文件之后可使用make来编译安装软件. configure的配置选项有哪些呢?现简单收集如下,不断更新中. 以gcc -v为例,可 ...

  9. OpenStack核心组件-cinder存储服务

    1. cinder 介绍 Block Storage 操作系统获得存储空间的方式一般有两种: 1)     通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...

  10. Alpha2的项目互评互测

    目录 @(Alpha2项目测试) 这个作业属于哪个课程 课程链接 这个作业要求在哪里 作业要求的链接 团队名称 你的代码我的发 这个作业的目标 其他参考文献 软件测试用例 姓名 学号 团队名称 李涵 ...