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. centos设置系统时间

    系统日期设定成1996年6月10日上午9点date -s 06/22/96date -s 09:00:00

  2. webuploader上传工具

    http://fex.baidu.com/webuploader/getting-started.html#显示用户选择 Html部分 首先准备dom结构,包含存放文件信息的容器.选择按钮和上传按钮三 ...

  3. Es6里面的解析结构

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. Android(java)学习笔记181:多媒体之图片画画板案例

    1.首先我们编写布局文件activity_main.xml如下: <RelativeLayout xmlns:android="http://schemas.android.com/a ...

  5. vscode vue template 下 style 的样式自动提示 #bug 这个搞完vue语法esLint就又不好使了,ERR

    网上都是 "*.vue": "vue",改成"*.vue": "html" 就ok了   "files.ass ...

  6. caffe layer注册机制

    Caffe内部维护一个注册表用于查找特定Layer对应的工厂函数(Layer Factory的设计用到了设计模式里的工厂模式).Layer_factory的主要作用是负责Layer的注册,已经注册完事 ...

  7. table、tr、td表格的行、单元格等属性说明

    table.tr.td表格的行.单元格等属性说明 <table>标签定义HTML表格.简单的HTML表格由table元素以及一个或多个tr.th或td元素组成. tr元素定义表格行,th元 ...

  8. django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module

    pip3 install mysqlclient try again python manage.py makemigrations python manage.py migrate

  9. 02.28 day03

    print(1 or 3 > 2 and 4 < 5 or 6 and 2 < 7)## while True:# print(11)# print(22)# # break# # ...

  10. Angular JavaScript内存溢出问题 (FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory)

    方法一和方法二参考:https://www.cnblogs.com/liugang-vip/p/6857595.html 方法一:my-project/node_modules/.bin 下增大内存( ...