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自动机的应用的更多相关文章

  1. 一道cf水题再加两道紫薯题的感悟

    . 遇到一个很大的数除以另一个数时,可以尝试把这个很大的数进行,素数因子分解. . 遇到多个数的乘积与另一个数的除法时,求是否能整除,可以先求每一个数与分母的最大公约数,最后若分母数字为1,则证明可整 ...

  2. [hdu3065]病毒侵袭持续中(AC自动机)

    题意:给出多种病毒的号码和特征码,计算在某串中各病毒匹配的次数. 解题关键:AC自动机模板题,多组输入坑人. #include<bits/stdc++.h> using namespace ...

  3. ACM/ICPC 之 两道dijkstra练习题(ZOJ1053(POJ1122)-ZOJ1053)

    两道较为典型的单源最短路径问题,采用dijkstra解法 本来是四道练习题,后来发现后面两道用dijkstra来解的话总觉得有点冗余了,因此暂且分成三篇博客(本篇以及后两篇). ZOJ1053(POJ ...

  4. 两道面试题,带你解析Java类加载机制

    文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...

  5. 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)

    本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...

  6. 『ACM C++』Virtual Judge | 两道基础题 - The Architect Omar && Malek and Summer Semester

    这几天一直在宿舍跑PY模型,学校的ACM寒假集训我也没去成,来学校的时候已经18号了,突然加进去也就上一天然后排位赛了,没学什么就去打怕是要被虐成渣,今天开学前一天,看到最后有一场大的排位赛,就上去试 ...

  7. (转)关于inode和block的两道企业面试题

    关于inode和block的两道企业面试题 原文:http://www.tk4479.net/xiaolong361/article/details/52373374 一.一个100M的磁盘分区,分别 ...

  8. 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制

    你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...

  9. 穷举(四):POJ上的两道穷举例题POJ 1411和POJ 1753

    下面给出两道POJ上的问题,看如何用穷举法解决. [例9]Calling Extraterrestrial Intelligence Again(POJ 1411) Description A mes ...

随机推荐

  1. net MVC 四种基本 Filter

    四种基本 Filter 概述 MVC框架支持的Filter可以归为四类,每一类都可以对处理请求的不同时间点引入额外的逻辑处理.这四类Filter如下表:   使用内置的Authorization Fi ...

  2. AJPFX关于枚举,泛型详解

    枚举类型是JDK5.0的新特征.Sun引进了一个全新的关键字enum来定义一个枚举类.下面就是一个典型枚举类型的定义:public enum Color{RED,BLUE,BLACK,YELLOW,G ...

  3. websocket 加layim实现在线聊天系统

    实现流程: 1.浏览器连接服务器时保存所有用户id以及对应的唯一session(session用户用户消息推送). 1.1:判断登录用户是否有离线消息(个人消息以及群消息),有则将离线消息进行推送给登 ...

  4. 实用工具特别推荐 BGInfo

    https://docs.microsoft.com/en-us/sysinternals/downloads/bginfo 介绍 您在办公室中走过多少次,需要点击几个诊断窗口,提醒自己其配置的重要方 ...

  5. (一) Docker in Docker

    一.  背景介绍 工作中,要实现在docker中运行docker,实现镜像的拉取,创建,修改,上传等操作. 尝试过在docker中,安装docker.行不通,服务起不来. 而且直接在 docker 容 ...

  6. JQQ文字素材

    1.十二生肖:子鼠.丑牛.寅虎.卯兔.辰龙.巳舍.午马.未羊.申猴.酉鸡.戌狗.亥猪.丙申年(2016)乙未年(2015)甲午年(2014)癸巳年(2013)壬辰年(2012)辛卯年(2011)庚寅年 ...

  7. 网新恩普(W 笔试)

    选择题 1.一桶有黄色,绿色,红色三种,闭上眼睛抓取同种颜色的两个.抓取多少个就可以确定你肯定有两个同一颜色的球? 答案: 4次 1.最坏打算抓3次都是不同颜色的黄.绿.红,此时,三种颜色的球各抓了一 ...

  8. 字符串类型:str, bytes 的区别

    Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分. 文本总是 Unicode,由 str 类型表示, 二进制数据则由 bytes 类型表示. Python 3不会以任意隐式的方 ...

  9. RestTemplate Hashmap变为LinkedHashMap源码解读

    使用restTemplate远程调用服务,正常应该接收List<HashMap>数据,但实际却是List<LikedHashMap>经过不断地debug,终于找到了数据被转换成 ...

  10. 剑指Offer(Python)

    014-链表中倒数第k个结点 用快慢指针:p2比p1先走到k:间隔了k-1)步,然后再一起走,当p2为最后一个时,p1就为倒数第k个数 class ListNode: def __init__(sel ...