病毒Virus

一本通P1396 病毒Virus

题目简述

给定\(k\)个被病毒感染了的字符串,知道这\(k\)个字符串原本是按字典序从小到大排列,最后给出一个待复原的字符串\(s\),要求根据上面的\(k\)个被感染的字符串复原\(s\)

  • 数据范围

\(k≤50000\)


所需算法

拓扑排序&模拟

前置知识

如果想了解拓扑排序欢迎来踩我的另一篇博客呀qvq


解题思路

感觉有点没读懂或者没思路?

那我们通过思考几个问题来找出思路:

  • \(k\)个被感染的字符串能为我们带来什么?

因为这\(k\)个字符串原本是按字典序排列的,所以是有序的;被病毒感染只会改变原来字符串的样子,但并不会影响原来的排序!

所以我们可以根据这\(k\)个字符串得出原字符\(x\)和感染后的字符\(y\)之间的对应关系!(可以理解为一一对应的映射关系)

  • 怎么找到这种映射关系?

这里我想到的做法是:双层循环+逐位查询+拓扑排序

说白点就是先模拟字典序排序的过程:如果两个字符串的第\(i\)位相等,则判断第\(i+1\)位,直到其中一个字符串完结

在这个过程中我们找到一个两个字符不同的位置,就进行连边和入度累加的操作,之后使用拓扑排序便能得到映射关系

  • 怎么想到的拓扑排序?

为了方便理解,我们插入理解一下样例:

  1. 先通过模拟字典序排序过程,我们可以得到如下的字符大小序列:\(c<e<d<a<b\) 和 \(e<a\)

  2. 那么映射关系即:\(c->a,e->b,d->c,a->d,b->e\)(注意箭头前的是被感染后的字符,箭头后的是原始字符)

找到了一个感觉没有?qwq

\(c<e<d<a<b\)这个即是拓扑序列!然后根据这个拓扑序列我们就能够找到映射关系!


代码Code

思路就是如上这么多了,理解后应该就能A掉这道题了,只是敲代码需要细心一点

现在先放出每个关键步骤的代码段(有注释),最后会放上完整的AC代码(无注释)

  • 模拟字典序排序
for(register int i=1;i<=n;i++) {  //循环1-n个字符串,这里的n相当于题目中的k(个人习惯啦qwq)
for(register int j=i+1;j<=n;j++) { //循环在i之后的字符串
int l=0; //l枚举字符串的位置
while(l<word[i].length()&&l<word[j].length()) { //匹配长度小于两个字符串的最小长度
flag[word[i][l]-'0']=1; //标记一下出现过,后面会用
if(word[i][l]==word[j][l]) l++; //相同则不管
else {
flag[word[j][l]-'0']=1;
in[word[j][l]-'0']++; //不同说明i串位置字符的字典序先于j串位置字符的字典序
add(word[i][l]-'0',word[j][l]-'0'); //连边+入度累加
break; //找到一位后面的就不用比较了
}
}
}
}
  • 拓扑排序
for(register char i='a';i<='z';i++) {  //如果这个字符出现过且入度为0(即字典序最先),就入队
if(flag[i-'0']==1&&in[i-'0']==0) q.push(i-'0');
}
while(!q.empty()) {
int x=q.front();
q.pop();
if(ans[x]!=0) { //这里是判断一个感染字符对应多个原始字符的错误情况
printf("0");
return 0;
}
ans[x]=sum; //注意ans是一个整型map
sum++;
for(register int i=head[x];i;i=e[i].net) { //遍历所有字典序在x之后的字符
int v=e[i].to;
in[v]--;
if(in[v]==0) q.push(v);
}
}
  • 完整代码
#include <bits/stdc++.h>
using namespace std;
queue<int> q;
map<int,int> ans;
string word[50002];
int n,tot,sum=97,in[201],head[201],flag[201]; struct node {
int to,net;
} e[50001]; inline void add(int u,int v) {
e[++tot].to=v;
e[tot].net=head[u];
head[u]=tot;
} int main() {
scanf("%d",&n);
for(register int i=1;i<=n;i++) {
cin>>word[i];
}
for(register int i=1;i<=n;i++) {
for(register int j=i+1;j<=n;j++) {
int l=0;
while(l<word[i].length()&&l<word[j].length()) {
flag[word[i][l]-'0']=1;
if(word[i][l]==word[j][l]) l++;
else {
flag[word[j][l]-'0']=1;
in[word[j][l]-'0']++;
add(word[i][l]-'0',word[j][l]-'0');
break;
}
}
}
}
cin>>word[n+1];
for(register char i='a';i<='z';i++) {
if(flag[i-'0']==1&&in[i-'0']==0) q.push(i-'0');
}
while(!q.empty()) {
int x=q.front();
q.pop();
if(ans[x]!=0) {
printf("0");
return 0;
}
ans[x]=sum;
sum++;
for(register int i=head[x];i;i=e[i].net) {
int v=e[i].to;
in[v]--;
if(in[v]==0) q.push(v);
}
}
for(register int i=0;i<word[n+1].length();i++) { //如果对应不完,那也是一种错误情况
if(ans[word[n+1][i]-'0']==0) {
printf("0");
return 0;
}
}
for(register int i=0;i<word[n+1].length();i++) {
cout<<char(ans[word[n+1][i]-'0']);
}
return 0;
}

病毒Virus的更多相关文章

  1. sublimeText jsformat 插件被当做病毒 virus

    最近在个只可往他里面发邮件,不能往外上任何互联网的地方工作,用 sublimetext 要装个sublime 插件 jsformat 十分麻烦.用gmail邮箱发总是报病毒. 最后挨个尝试,发现是 j ...

  2. 对病毒Virus.Win32.Ramnit.B的研究

  3. 最近碰到了一个病毒木马:virus.win32.ramnit.B

    由于 使用了 简单游 平台上的挂机工具: 番茄-自动人机对战免费版1217  ,使用了很久,头段时间家里电脑 360提示有病毒,本来我一直忽略的,但 我扫描了一下,大量的这个木马,于是 吧 简单游卸载 ...

  4. Web测试介绍2一 安全测试

            安全测试是在IT软件产品的生命周期中,特别是产品开发基本完成到发布阶段,对产品进行检验以验证产品符合安全需求定义和产品质量标准的过程. 主要安全需求包括: (i) 认证 Authent ...

  5. [A Top-Down Approach][第一章 计算机网络和因特网]

    [A Top-Down Approach][第一章 计算机网络和因特网] 标签(空格分隔): 计算机网络 介绍基本术语和概念 查看构成网络的基本硬件和软件组件. 从网络的边缘开始,考察在网络中运行的端 ...

  6. virus.win32.parite.H病毒的查杀方法

    virus.win32.parite.H病毒的查杀方法 昨天电脑中了virus.win32.parite.H病毒,搞了2个多小时最终搞定了.以下记录下我的解决方法. 第一步:下载Win32.Parit ...

  7. virus.win32.parite.H查杀病毒的方法

    virus.win32.parite.H病毒的查杀方法 昨天电脑中了virus.win32.parite.H病毒,搞了2个多小时最终搞定了.以下记录下我的解决方法. 第一步:下载Win32.Parit ...

  8. [LeetCode] Contain Virus 包含病毒

    A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls. ...

  9. [Swift]LeetCode749. 隔离病毒 | Contain Virus

    A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls. ...

随机推荐

  1. Java实现 LeetCode 371 两整数之和

    371. 两整数之和 不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a .b ​​​​​​​之和. 示例 1: 输入: a = 1, b = 2 输出: 3 示例 2: 输入: ...

  2. Java实现 LeetCode 283 移动零

    283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序. 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必 ...

  3. SQL Server使用Offset/Fetch Next实现分页

    T-SQL实现分页 ,查找指定范围内的数据 首先,正常的查询是这样的 使用分页后 select * from Products order by ProductID offset X rows fet ...

  4. 第八届蓝桥杯JavaC组国(决)赛真题

    解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.数位和 题目描述 数学家高斯很小的时候就天分过人.一次老师指定的算数题目是:1+2+-+100. 高斯立即做出答案:5050! 这次你 ...

  5. java实现第六届蓝桥杯打印大X

    打印大X 打印大X 小明希望用星号拼凑,打印出一个大X,他要求能够控制笔画的宽度和整个字的高度. 为了便于比对空格,所有的空白位置都以句点符来代替. 要求输入两个整数m n,表示笔的宽度,X的高度.用 ...

  6. Linux 文件特殊权限-Sticky BIT

    SBIT粘着位作用 只对目录有效 普通用户对该目录拥有w和x权限,即普通用户可以在此目录有写权限 如果没有粘着位,普通拥有写权限,就可以删除目录下所有文件,包括其他用户创建的文件,一旦有粘着位,只有r ...

  7. shell中文本内容多行变一行的技巧

    在linux下有时可能需要将多行的值转成一行.其实现的方法有很多种.笔者将自己曾经用过的方法在些分享. 如有一文本文件5201351.txt,文本的内容如下: 现我们可以通过如下方法将文本内容转成一行 ...

  8. OO第一作业周期(前四周)总结

    前言:回顾这三次的作业,在一次次的练习下渐渐理解了一些Java的一些基本知识和类与对象的含义与用法,也找到了很多自身的不足和问题,主要是反映类与类之间的关系没有理解到位,这次总结后又有了新的感悟和理解 ...

  9. 【深度思考】JDK8中日期类型该如何使用?

    在JDK8之前,处理日期时间,我们主要使用3个类,Date.SimpleDateFormat和Calendar. 这3个类在使用时都或多或少的存在一些问题,比如SimpleDateFormat不是线程 ...

  10. [转] 图解单片机下载程序电路原理之USB转串口线、CH340、PL2303、MAX232芯片的使用

    点击阅读原文 目前为止,我接触单片机已有不少时日,从选择元器件.原理图.PCB.电路硬件调试.软件开发也算小有心得 .单片机软件开发里面第一步当属下载程序了,如果这一步都有问题,那么后面的一切便无从谈 ...