病毒的侵扰和再侵扰两道AC自动机的应用
HDU2896 病毒的侵扰
http://vjudge.net/problem/viewProblem.action?id=16404
题目大意:
记录每个病毒的编号,并给出一些网站的源码,分别输出网站及其对应编号中所含病毒的编号,没有就不输出
最后输出有病毒网站的个数
这道题需要注意的是这个所有ASCII码均会用到,所以我之前傻傻地写str[i]-'a'还不知为什么会错简直苦逼~~
这里直接用ch[now][str[i]]找到对应位置即可
因为要记录编号,为了防止重复访问,我对query中进行了一个visit[]数组访问进行判断的操作
query函数如下:
void query(char *str){
int len=strlen(str);
int now=root,ret=;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root&&(!visit[k]&&val[k])){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(!visit[k])sum++,ans[ret++]=val[k],visit[k]=;
k=last[k];
}
}
}
用ans[]记录所有编号,sum记录病毒个数,那么就可以在main函数进行sort(ans,ans+sum)进行排序好就可以输出了
总代码如下:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define N 500*201
char str[];
int ans[],visit[N],sum;
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root,cnt;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=,cnt=;
root=newnode();
}
void add(char *s){
int len=strlen(s);
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s[i]];
if(!k) k=newnode();
now=k;
}
cnt++;
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root,ret=;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root&&(!visit[k]&&val[k])){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(!visit[k])sum++,ans[ret++]=val[k],visit[k]=;
k=last[k];
}
}
}
}ac;
int main()
{
int n,m;
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
scanf("%s",str);
ac.add(str);
}
ac.get_fail();
scanf("%d",&m);
int c=;
for(int i=;i<=m;i++){
sum=;
scanf("%s",str);
memset(visit,,sizeof(visit));
ac.query(str);
sort(ans,ans+sum);
if(sum>){
printf("web %d:",i);
for(int j=;j<sum;j++) printf(" %d",ans[j]);
printf("\n");
c++;
}
}
printf("total: %d\n",c);
}
return ;
}
HDU 3065病毒再侵扰
http://vjudge.net/problem/viewProblem.action?id=16405
给一堆带序号的病毒,再给一个网站源码,问这个网站有哪些病毒,分别有几个,输出病毒码和其对应的个数
这里的query主串中因为会重复模式串,所以不能将val[]数组进行清零,要让他每次都能访问到
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
这道题和上一道字符串有所区别,这里病毒码只有26个大写字母,主串可以是128个ASCII码的任何字符
当然直接在AC结构体中定义ch[N][128]也并未超内存
这是我最开始写的代码:
Memory: 16756 KB | Time: 296 MS | |
Language: G++ |
Result: Accepted |
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
#define N 1000*52
char str[];
int ans[];
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=;
root=newnode();
}
void add(string s,int cnt){
int len=s.length();
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s.at(i)];
if(!k) k=newnode();
now=k;
}
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
now=ch[now][str[i]];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
}ac;
int main()
{
int n;
string s[];
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
cin>>s[i+];
ac.add(s[i+],i+);
}
ac.get_fail();
scanf("%s",str);
ac.query(str);
for(int i=;i<=;i++){
if(ans[i]>) cout<<s[i]<<": "<<ans[i]<<endl;
}
}
return ;
}
但是我们定义一个ch[N][26]的数组却可以减少更多的内存占用,那么我们每次找位置都是用now=ch[now][str[i]-'A']来进行操作
在query中面对不在A~Z范围内的数,我们就利用一个if判断条件来做
if(str[i]<'A'||str[i]>'Z') now=root;//因为不在A~Z范围内的数是不存在有字母能跟它进行匹配的,所以直接将指针移回根节点重新进行判断
else{
}
Memory: 5584 KB | Time: 187 MS | |
Language: G++ | Result: Accepted |
#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
#define N 1000*52
char str[];
int ans[];
struct AC{
int ch[N][],fail[N],val[N],last[N],tmp,root;
int newnode(){
val[tmp]=;
memset(ch[tmp],,sizeof(ch[tmp]));
return tmp++;
}
void init(){
tmp=;
root=newnode();
}
void add(string s,int cnt){
int len=s.length();
int now=root;
for(int i=;i<len;i++){
int &k=ch[now][s.at(i)-'A'];
if(!k) k=newnode();
now=k;
}
val[now]=cnt;
}
void get_fail(){
fail[root]=root;
queue<int> q;
for(int i=;i<;i++){
int v=ch[root][i];
if(v)
fail[v]=last[v]=,q.push(v);
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=;i<;i++){
int v=ch[now][i];
if(!v) ch[now][i]=ch[fail[now]][i];
else{
fail[v]=ch[fail[now]][i];
last[v]=val[fail[v]]?fail[v]:last[fail[v]];
q.push(v);
}
}
}
}
void query(char *str){
int len=strlen(str);
int now=root;
for(int i=;i<len;i++){
if(str[i]>'Z'||str[i]<'A') now=root;
else{
now=ch[now][str[i]-'A'];
int k=now;
while(k!=root){//这是要循环到找到fail值为root的时候或者找到匹配的字符串的时候,否则一直向前找fail值,
if(val[k]>) ans[val[k]]++;
k=last[k];
}
}
}
}
}ac;
int main()
{
int n;
string s[];
while(scanf("%d",&n)!=EOF){
memset(ans,,sizeof(ans));
ac.init();
for(int i=;i<n;i++){
cin>>s[i+];
ac.add(s[i+],i+);
}
ac.get_fail();
scanf("%s",str);
ac.query(str);
for(int i=;i<=;i++){
if(ans[i]>) cout<<s[i]<<": "<<ans[i]<<endl;
}
}
return ;
}
病毒的侵扰和再侵扰两道AC自动机的应用的更多相关文章
- 一道cf水题再加两道紫薯题的感悟
. 遇到一个很大的数除以另一个数时,可以尝试把这个很大的数进行,素数因子分解. . 遇到多个数的乘积与另一个数的除法时,求是否能整除,可以先求每一个数与分母的最大公约数,最后若分母数字为1,则证明可整 ...
- [hdu3065]病毒侵袭持续中(AC自动机)
题意:给出多种病毒的号码和特征码,计算在某串中各病毒匹配的次数. 解题关键:AC自动机模板题,多组输入坑人. #include<bits/stdc++.h> using namespace ...
- ACM/ICPC 之 两道dijkstra练习题(ZOJ1053(POJ1122)-ZOJ1053)
两道较为典型的单源最短路径问题,采用dijkstra解法 本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇). ZOJ1053(POJ ...
- 两道面试题,带你解析Java类加载机制
文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- 『ACM C++』Virtual Judge | 两道基础题 - The Architect Omar && Malek and Summer Semester
这几天一直在宿舍跑PY模型,学校的ACM寒假集训我也没去成,来学校的时候已经18号了,突然加进去也就上一天然后排位赛了,没学什么就去打怕是要被虐成渣,今天开学前一天,看到最后有一场大的排位赛,就上去试 ...
- (转)关于inode和block的两道企业面试题
关于inode和block的两道企业面试题 原文:http://www.tk4479.net/xiaolong361/article/details/52373374 一.一个100M的磁盘分区,分别 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- 穷举(四):POJ上的两道穷举例题POJ 1411和POJ 1753
下面给出两道POJ上的问题,看如何用穷举法解决. [例9]Calling Extraterrestrial Intelligence Again(POJ 1411) Description A mes ...
随机推荐
- memcached随笔练习
实验环境: RHEL 6.5 (已关闭selinux,iptables) 首先部署LNMP环境,该步骤采用源码编译安装 安装Nginx-1.8.0 准备软件包:nginx-1.8.0.tar.gz 下 ...
- Oracle、MySQL和SqlServe分页查询的语句区别
★先来定义分页语句将要用到的几个参数: int currentPage ; //当前页 int pageRecord ; //每页显示记录数 以之前的ADDRESSBOOK数据表为例(每页显示10条记 ...
- js获取服务器生成并返回客户端呈现给客户的控件id的方法
var repeaterId = '<%=rpData.ClientID %>'; //Repeater的客户端IDvar rows = <%=rpData.Items.Count% ...
- 洛谷 P2319 [HNOI2006]超级英雄
题目描述 题目描述 现在电视台有一种节目叫做超级英雄,大概的流程就是每位选手到台上回答主持人的几个问题,然后根据回答问题的多少获得不同数目的奖品或奖金.主持人问题准备了若干道题目,只有当选手正确回答一 ...
- Netbeans Makefile: recipe for target 'XXX' failed 运行failed(退出值 -1073741511 找不到C/C++库文件,关键字
今天不知怎么的又出错了 吐血了 找不到NULL new等关键字了 看到知乎上有人和我一个问题,怎么办?很简单卸载了以前的cygwin和netbeans然后重装,我重装时没有把以前的cygwin ...
- android和IOS长连接区别
http://blog.csdn.net/zhangzeyuaaa/article/details/39028369 首先我们必须知道,所有的推送功能必须有一个客户端和服务器的长连接,因为推送是由服务 ...
- class 写在 import的位置 类的名字第一个字母大写 后面没括号 ES6
class 写在 import的位置 类的名字第一个字母大写 后面没括号 class ObTableDataClass {}或者 const ObTableDataClass = class { in ...
- 浏览器title失去焦点时改变title
document.addEventListener('visibilitychange', function() { var isHidden = document.hidden; if (isHid ...
- RNN静态与动态
静态.多层RNN:import numpy as np import tensorflow as tf # 导入 MINST 数据集 from tensorflow.examples.tutorial ...
- CPP-STL:vector容器
1. vector容器简介: vector向量容器是一种随机访问的数组类型,它提供了对数组元素的快速访问.随机访问,以及在序列尾部快速.随机地插入和删除操作.它类似于数据结构中的队列.数组和堆 ...