模拟算法总述

news2024/11/29 1:45:03

模拟

1.模拟算法介绍

模拟算法通过模拟实际情况来解决问题,一般容易理解但是实现起来比较复杂,有很多需要注意的细节,或者是一些所谓很”麻烦”的东西。
模拟题一般不涉及太难的算法,一般就是由较多的简单但是不好处理的部分组成的,考察选手的细心程度和整体的逻辑思维。
一般为了使得模拟题写的逻辑清晰一些,经常会写比较多的小函数来帮助解题,例如int和string的相互转换、回文串的判断、日期的转换、各种特殊条件的判断等等。

2.例题

2.1 地址转换

题目描述

Excel是最常用的办公软件。每个单元格都有唯一的地址表示。比如:第12行第4列表示为:“D12”,第5行第255列表示为"IU5"。
事实上,Excel提供了两种地址表示方法,还有一种表示法叫做RC格式地址。第12行第4列表示为"R12C4",第5行第255列表示为"R5C255""。你的任务是:编写程序,实现从RC地址格式到常规地址格式的转换。

输入描述
用户先输入一个整数 n ( n < 100 ) n (n <100) n(n<100),表示接下来有 n n n行输入数据。
接着输入的n行数据是RC格式的Excel单元格地址表示法。

输出描述
程序则输出 n n n行数据,每行是转换后的常规地址表示法。

输入输出样例

示例

输入

2
R12C4
R5C255

输出

D12
IU5

思路

这个题本质就是进制的转化,Excel表中的列可以转换为26进制。

代码

#include <bits/stdc++.h>
using namespace std;

int n, r, c;
char a, b;
int main() {
	cin >> n;
	while(n --) {
		cin >> a >> r >> b >> c;
		if(b <= 26) {
			char d = c + 'A' - 1;
			cout << d << r << endl;
		} else if(b > 26) {
			char d = 'A' + c/26 - 1;
			char e = 'A' + c%26 - 1;
			cout << d << e << c << endl;
		}
	}	
	return 0;
}

2.2 DNA序列修正

问题链接:https://www.lanqiao.cn/problems/3904/learning/page=1&first_category_id=1&name=DNA

问题描述
在生物学中, D N A DNA DNA序列的相似性常被用来研究物种间的亲缘关系。现在我们有两条 D N A DNA DNA序列,每条序列由 A 、 C 、 G 、 T A、C、G、T ACGT四种字符组成,长度相同。但是现在我们记录的 D N A DNA DNA序列存在错误,为了严格满足 D N A DNA DNA序列的碱基互补配对即 A − T A-T AT C − G C-G CG,我们需要依据第—条 D N A DNA DNA序列对第二条 D N A DNA DNA序列进行以下操作:
1.选择第二条 D N A DNA DNA序列的任意两个位置,交换他们的字符。
2.选择第二条 D N A DNA DNA序列任意一个位置,将其字符替换为 A 、 C 、 G 、 T A、C、G、T ACGT中的任何一个。
需要注意的是:每个位置上的碱基只能被操作一次!
你的任务是通过最小的操作次数,使第二条 D N A DNA DNA序列和第一条 D N A DNA DNA序列互补。并且已知初始两条 D N A DNA DNA序列长度均为 N N N

输入格式
第一行包含一个整数 N N N ( 1 < N < 1 0 3 ) (1 <N<10^3) (1<N<103),表示 D N A DNA DNA序列的长度。
接下来的两行,每行包含一个长度为 N N N的字符串,表示两条 D N A DNA DNA序列。

输出格式
输出一个整数,表示让第二条DNA序列和第—条DNA序列互补所需的最小操作次数。

样例输入

5
ACGTG
ACGTC

样例输出

2

样例说明

将第二条DNA序列中的第一个和第四个碱基交换,将第二个和第三个碱基交换即可完成全部配对,共操作两次。

思路

我们可以考虑贪心的思路,因为每次修改操作只能修正一个位置,就是操作和得分比是1∶1;如果我们考虑通过交换来同时修正两个位置,那么操作和得分比就是1∶2,我们应当尽可能多地使用该操作。那么整个过程就是:

1.从左到右扫描第一条DNA序列和第二条DNA序列的每一个位置,检查它们是否互补。

2.**如果某个位置不互补,我们需要寻找第二条DNA序列中后续位置的碱基,看是否可以通过交换使这两个位置都互补。**如果可以,我们就进行交换。注意:**这里必须是交换后,两个位置都互补,否则交换没有意义。**如果交换后,一个位置互补,另一个位置不互补,此次交换等价于直接改变元素,所以不能交换。同时,这样的交换还会影响到交换两个位置都互补的情况。简单来说,如果交换的条件是:有一个位置互补,另一位置不互补也交换,导致后面交换两个位置都互补的情况不存在了,就会影响最终的结果。

3.如果在后续位置找不到可以交换的碱基,说明这个位置只能通过替换来满足要求。因为每个位置只能修改一次,所以我们不能把不配对的碱基交换到当前位置作为中转站,则只能进行修改。

4.每次交换或替换,操作计数器增加1。

5.最后输出操作计数器的值。

代码

#include<iostream>
#include<map>
using namespace std;

map<char, int> mp{
        {'A', 0},
        {'C', 1},
        {'G', 2},
        {'T', 3}
};

int main() {
    int n;
    cin >> n;
    string a, b;
    cin >> a >> b;
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        if (mp[a[i]] + mp[b[i]] != 3) {
            for (int j = i + 1; j < n; j++) {
                if (mp[a[i]] + mp[b[j]] == 3 && mp[a[j]] + mp[b[i]] == 3) {
                    swap(b[i], b[j]);
                    break;
                }
            }
            cnt++;
        }
    }
    cout << cnt << endl;
    return 0;
}

2.3 拉马车

问题链接:https://www.lanqiao.cn/problems/101/learning/page=1&first_category_id=1&name=%E6%8B%89%E9%A9%AC%E8%BD%A6

题目描述

小的时候,你玩过纸牌游戏吗?有一种叫做"拉马车"的游戏,规则很简单,却很吸引小朋友。其规则简述如下:

假设参加游戏的小朋友是 A A A B B B,游戏开始的时候,他们得到的随机的纸牌序列如下:
A A A方: [ K , 8 , X , K , A , 2 , A , 9 , 5 , A ] [K, 8, X, K, A, 2, A, 9, 5, A] [K,8,X,K,A,2,A,9,5,A]
B B B方: [ 2 , 7 , K , 5 , J , 5 , Q , 6 , K , 4 ] [2, 7, K, 5, J, 5, Q, 6, K, 4] [2,7,K,5,J,5,Q,6,K,4]
其中的 X X X表示" 10 10 10",我们忽略了纸牌的花色。
A A A方开始, A 、 B A、B AB双方轮流出牌。
当轮到某一方出牌时,他从自己的纸牌队列的头部拿走—张,放到桌上,并且压在最上面—张纸牌上(如果有的话)。

此例中,游戏过程:
A A A K K K B B B 2 2 2 A A A 8 8 8 B B B 7 7 7 A A A X X X,此时桌上的序列为:
K , 2 , 8 , 7 , X K, 2,8,7,X K,2,8,7,X
当轮到 B B B出牌时,他的牌 K K K与桌上的纸牌序列中的 K K K相同,则把包括 K K K在内的以及两个 K K K之间的纸牌都赢回来,放入自己牌的队尾。注意:为了操作方便,放入牌的顺序是与桌上的顺序相反的。
此时, A A A B B B双方的手里牌为:
A A A方: [ K , A , 2 , A , 9 , 5 , A ] [K,A,2,A,9,5,A] [K,A,2,A,9,5,A]
B B B方: [ 5 , J , 5 , Q , 6 , K , 4 , K , X , 7 , 8 , 2 , K ] [5,J,5,Q,6,K ,4,K ,X,7,8,2,K] [5,J,5,Q,6,K,4,K,X,7,8,2,K]赢牌的一方继续出牌。也就是 B B B接着出 5 5 5 A A A K K K B B B J J J A A A A A A B B B 5 5 5,又赢牌了。此时桌上的序列为:
5 , K , J , A , 5 5,K , J,A,5 5,K,J,A,5

此时双方手里牌:

A A A方: [ 2 , A , 9 , 5 , A ] [2,A,9,5,A] [2,A,9,5,A]

B B B方: [ Q , 6 , K , 4 , K , X , 7 , 8 , 2 , K , 5 , A , J , K , 5 ] [Q,6,K ,4,K,X ,7,8,2,K,5,A,J, K,5] [Q,6,K,4,K,X,7,8,2,K,5,A,J,K,5]

注意:更多的时候赢牌的一方并不能把桌上的牌都赢走,而是拿走相同牌点及其中间的部分。但无论如何,都是赢牌的一方继续出牌,有的时候刚一出牌又赢了,也是允许的。
当某一方出掉手里最后—张牌,但无法从桌面上赢取牌时,游戏立即结束。
对于本例的初始手牌情况下,最后 A A A会输掉,而 B B B最后的手里牌为:
9 K 2 A 62 K A X 58 K 57 K J 5 9K2A62KAX58K57KJ5 9K2A62KAX58K57KJ5
本题的任务就是已知双方初始牌序,计算游戏结束时,赢的一方手里的牌序。当游戏无法结束时,输出 − 1 -1 1

输入描述

输入为 2 2 2行, 2 2 2个串,分别表示 A 、 B A、B AB双方初始手里的牌序列。我们约定,输入的串的长度不超过 30 30 30 2 J 9 A 7 Q A 6 Q 6889977 2J9A7QA6Q6889977 2J9A7QA6Q6889977

输出描述

输出为 1 1 1行, 1 1 1个串,表示 A A A先出牌,最后赢的一方手里的牌序。

输入输出样例

示例

输入

96J5A898QA
6278A7Q973

输出

2J9A7QA6Q6889977

思路

代码使用string、stack去模拟这个过程。 A A A B B B双方的出牌是从头部拿走一张,可以用队列来存储字符,也可以用string类的模仿字符队列。

xxxx.erase(0, 1) // 实现头部数据的弹出

stack的入栈和出栈操作与牌堆类似,所以用stack模拟牌堆。

在题目中,交换A、B双方的操作权是一大难点。下面给出了详细的解决过程。使用到了指针、bool变量来完成。

代码

#include <bits/stdc++.h>
using namespace std; 


bool a[128]; // a[i]表示牌堆中是否存在i这张牌 
int main() { 
  string A, B; 
  cin >> A >> B; 
  stack<char> S; // 用栈作为牌堆
  S.push(A[0]); a[A[0]-0]=1; A.erase(0,1); // A先出牌
  bool flag=1; // flag控制到谁出牌 
  int times=0; // times表示出牌次数,超过10000认为会无限循环 
  while(A.length() && B.length() && times<10000){ 
    string* sp=flag?&B:&A; // flag为1时B出牌,将string指针指向B,方便实现B的出牌和收牌 
    char tmp=(*sp)[0];
    S.push(tmp); sp->erase(0,1); // 玩家出牌 
    if(a[tmp-0]==0) { a[tmp-0]=1; flag = !flag; } // 牌堆中没有当前出的牌,牌权更换 
    else{ // 若包含当前字符,收回一部分牌 
      *sp += S.top(); S.pop(); // 收回刚出的那张牌,位于栈顶 
      while(S.top()!=tmp){ *sp += S.top(); a[S.top()-0] = 0; S.pop(); } //一直收牌到与所出牌相同的另一张牌处 
      *sp += S.top(); a[S.top()-0] = 0; S.pop(); 
    } 
    times++; 
  } 
  if(times>=10000) return -1; 
  if(A.length()) cout<<A; else cout<<B; 
  return 0; 
}

2.4 机器人行走

题目链接:https://www.lanqiao.cn/problems/283/learning/page=1&first_category_id=1&name=%E6%9C%BA%E5%99%A8%E4%BA%BA%E8%A1%8C%E8%B5%B0

题目描述

某少年宫引进了一批机器人小车。可以接受预先输入的指令,按指令行动。小车的基本动作很简单,只有 3 3 3种:左转(记为 L L L),右转(记为 R R R),向前走若干厘米(直接记数字)。
例如,我们可以对小车输入如下的指令:
15 L 10 R 5 L R R 10 R 20 15L10R5LRR10R20 15L10R5LRR10R20
则,小车先直行 15 15 15厘米,左转,再走 10 10 10厘米,再右转,….
不难看出,对于此指令串,小车又回到了出发地。
你的任务是:编写程序,由用户输入指令,程序输出每条指令执行后小车位置与指令执行前小车位置的直线距离。

输入描述

用户先输入一个整数 n ( n < 100 ) n (n<100) n(n<100),表示接下来将有 n n n条指令。
接下来输入 n n n条指令。每条指令只由 L 、 R L、R LR和数字组成(数字是 0 0 0~ 100 100 100之间的整数)
每条指令的长度不超过 256 256 256个字符。

输出描述
程序则输出 n n n行结果,每条结果表示小车执行相应的指令前后位置的直线距离。要求四舍五入到小数后 2 2 2位。

输入输出样例

示例

输入

5
L100R50R10
3LLL5RR4L12
LL
100R
5L5L5L5

输出

102.96
9.06
0.00
100.00
0.00

思路

这个题的难点分别包括模拟小车的方向和坐标、小车的指令与行驶距离的区分。

首先,解决小车的方向和坐标问题。使用int变量x,y分别代表小车的横纵坐标。使用int k代表小车的方向。

在这里插入图片描述

默认车的方向为 k = 0 k=0 k=0,如果想要实现右转, k = ( k + 1 ) k=(k+1) k=(k+1)% 4 4 4即可。如果想要实现左转, k = ( k + 3 ) k=(k+3) k=(k+3)% 4 4 4

实现函数为:

void move(int dis){
  if(k == 0)y += dis;
  else if(k == 1)x += dis;
  else if(k == 2)y -= dis;
  else x-= dis;
}

小车的指令与行驶距离的区分,可以使用if条件语句进行区分,当读到指令后,调整方向,如果读到数字,说明为距离,应该继续向后读,读完整个距离。

代码

#include <bits/stdc++.h>
using namespace std;

int n, x, y, k;
// k = 0向上走, k = 1向右走, k = 2向下走, k = 3向左走
void move(int dis){
  if(k == 0)y += dis;
  else if(k == 1)x += dis;
  else if(k == 2)y -= dis;
  else x-= dis;
}

int main(){
  cin >> n;     // 读取指令的个数
  while(n--){
    x = 0, y = 0, k = 0; // x, y代表坐标, k代表方向
    string str; // 接收当前的指令
    cin >> str;
    for(int i = 0;i < str.length();++i){
      if(str[i] == 'L')k = (k+3)%4; 
      else if(str[i] == 'R')k = (k+1)%4;
      else{
        int dis = str[i] - '0'; // 说明当前时为距离
        while(++i < str.length() && str[i]!='L' && str[i]!='R') // 完整读取当前的距离
          dis = dis*10 + str[i] - '0';
        move(dis);// 进行移动
        --i;//在寻找完整距离时, i的下标已经指向数字的下一位
      }
    }
    printf("%.2f\n", sqrt(x*x + y*y));
  }
  return 0;
}


; 
      else if(str[i] == 'R')k = (k+1)%4;
      else{
        int dis = str[i] - '0'; // 说明当前时为距离
        while(++i < str.length() && str[i]!='L' && str[i]!='R') // 完整读取当前的距离
          dis = dis*10 + str[i] - '0';
        move(dis);// 进行移动
        --i;//在寻找完整距离时, i的下标已经指向数字的下一位
      }
    }
    printf("%.2f\n", sqrt(x*x + y*y));
  }
  return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1529995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

xinference - 大模型分布式推理框架

文章目录 关于 xinference使用1、启动 xinference设置其他参数 2、加载模型3、模型交互 其它报错处理 - transformer.wte.weight 关于 xinference Xorbits Inference&#xff08;Xinference&#xff09;是一个性能强大且功能全面的分布式推理框架。 可用于大语言模型&#xff…

【重温设计模式】状态模式及其Java示例

状态模式的基本概念 在编程世界的大海中&#xff0c;各种设计模式就如同灯塔&#xff0c;为我们的代码编写指明方向。其中&#xff0c;状态模式是一种行为设计模式&#xff0c;它让你能在一个对象的内部状态改变时改变其行为&#xff0c;使得对象看起来就像改变了其类一样。这…

Flink中任务(Tasks)和任务槽(Task Slots)详解

Flink中任务&#xff08;Tasks&#xff09;和任务槽&#xff08;Task Slots&#xff09;详解 任务槽&#xff08;Task Slots&#xff09; Flink中每一个worker(也就是TaskManager)都是一个JVM进程&#xff0c;它可以启动多个独立的线程&#xff0c;来并行执行多个子任务&#…

从零开始搭建游戏服务器 第四节 MongoDB引入并实现注册登录

这里写目录标题 前言正文添加依赖安装MongoDB添加MongoDB相关配置创建MongoContext类尝试初始化DB连接实现注册功能测试注册功能实现登录逻辑测试登录流程 结语下节预告 前言 游戏服务器中, 很重要的一点就是如何保存玩家的游戏数据. 当一个服务端架构趋于稳定且功能全面, 开发…

Spring单元测试+Mockito

一&#xff0c;背景 单元测试基本上是开发逃不过的一个工作内容&#xff0c;虽然往往因为过于无聊&#xff0c;或者过于麻烦&#xff0c;而停止于项目的迭代之中&#xff0c;不了了之了。其实不是开发们懒&#xff0c;而是上头要求的测试覆盖率高&#xff0c;但是又没有好用的…

zookeeper快速入门(合集)

zookeeper作为一个分布式协调框架&#xff0c;它的创建就是为了方便或者简化分布式应用的开发。除了服务注册与发现之外&#xff0c;它还能够提供更多的功能&#xff0c;但是对于入门来说&#xff0c;看这一篇就够了。后续会讲zookeeper的架构设计与原理&#xff0c;比如zookee…

MySQL 数据库设计范式

第一范式&#xff08;1NF&#xff09; 每一列都是不可分割的原子数据项第二范式&#xff08;2NF&#xff09; 在1NF的基础上&#xff0c;非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖) 1.函数依赖A->B&#xff0c;如果通过A属性(属性组)的值…

[LeetBook]【学习日记】排序算法——归并排序

主要思想 归并排序是一种分治算法&#xff0c;其排序过程包括分和治分是指将要排序的序列一分为二、二分为四&#xff0c;直到单个序列中只有一个数治是指在分完后&#xff0c;将每两个元素重新组合&#xff0c;四合为二、二合为一&#xff0c;最终完成排序 图片作者&#xf…

python 实现把内层文件夹的文件,复制/剪切到外层文件夹

文章目录 如下图所示&#xff0c;收集了很多省市的文件&#xff0c;结果发现市一级的文件与区县一级的文件混在一起了。 接下来使用代码实现&#xff1a; 根据关键词识别出 市一级的文件&#xff1b;把市一级的文件&#xff0c;移动或者复制到省文件夹下&#xff1b;给出了py…

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+GTX 8b/10b编解码SFP光口传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收HLS图像缩放HLS多路视频拼接应用本方案的SDI…

前端静态开发案例-基于H5C3开发的仿照视频网站的前端静态页面-2 样式表部分和效果展示

原创作者&#xff1a;田超凡&#xff08;程序员田宝宝&#xff09; 版权所有&#xff0c;引用请注明原作者&#xff0c;严禁复制转载 charset "utf-8"; /* 程序员田宝宝原创版权所有&#xff0c;仿冒必究&#xff0c;该界面是仿照某视频网站官网开发的静态页面 */ …

【Thread 线程】线程的方法与状态

SueWakeup 个人中心&#xff1a;SueWakeup 系列专栏&#xff1a;学习Java 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f7; 友情赞助播出&#xff01; 目录 一个线程的生命周期 线程终止的原因 线程的方法 Thread 类的静态方法 1. 设置线程…

linux单机部署hadoop

1.下载安装包 https://archive.apache.org/dist/hadoop/common/ 2.上传压缩 3.修改配置文件 1)设置JDK的路径 cd /usr/local/software/hadoop-3.1.3/etc/hadoop vi hadoop-env.sh export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.402.b06-1.el7_9.x86_64/ 查看…

【数据结构和算法初阶(C语言)】二叉树的顺序结构--堆的实现/堆排序/topk问题详解---二叉树学习日记②1

目录 ​编辑 1.二叉树的顺序结构及实现 1.1 二叉树的顺序结构 2 堆的概念及结构 3 堆的实现 3.1堆的代码定义 3.2堆插入数据 3.3打印堆数据 3.4堆的数据的删除 3.5获取根部数据 3.6判断堆是否为空 3.7 堆的销毁 4.建堆以及堆排序 4.1堆排序---是一种选择排序 4.2升序建大堆&a…

微信小程序 canvas层级过高覆盖原生组件

一、背景 微信小程序中使用signature第三方插件完成签名效果&#xff0c;但真机调试时发现canvas层级过高遮挡了按钮 二、具体问题 问题原因&#xff1a;签名后点击按钮无法生效 问题代码&#xff1a; <template><view class"sign_page" v-cloak>&l…

nodejs基于vue超市信息管理系统flask-django-php

互联网的快速发展&#xff0c;使世界各地的各种组织的管理方式发生了根本性的变化&#xff0c;我国政府、企业等组织在上个世纪90年代就已开始考虑使用互联网来管理信息。由于以前的种种因素&#xff0c;比如网络的普及率不高&#xff0c;用户对它的认知度不够&#xff0c;以及…

计算机网络:数据交换方式

计算机网络&#xff1a;数据交换方式 电路交换分组交换报文交换传输对比 本博客介绍计算机之间数据交换的三种方式&#xff0c;分别是电路交换、分组交换以及报文交换。 电路交换 我们首先来看电路交换&#xff0c;在电话问世后不久&#xff0c;人们就发现要让所有的电话机都…

基于Spring Boot网络相册设计与实现

摘 要 网络相册设计与实现的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。 与安卓&#xff0c;iOS相比较起来&am…

【OCR】OCR开源文字识别工具

在日常的工作中&#xff0c;例如自动化测试开展时&#xff0c;经常涉及到一些验证码识别、文本识别、图像识别的场景&#xff0c;市面上虽也有很多识别工具&#xff0c;但质量、准确性参差不齐。 今天给大家推荐一个开源OCR项目:Umi-OCR&#xff0c;功能很强大&#xff0c;而且…

jquery 列表框可以手动修改(调用接口修改)

类似于这种 直接上代码 列表框 <td>//目的主要是获取属性名的(要更改的属性名) 在下面juqery的这一行(var field $(thisobj).prev(input).attr(name);)有体现<input type"hidden" name"voyage" value"${M_PSI_PERIOD_INFO.port}">…