「C++」简单模拟

· 浏览次数 : 0

小编点评

**A. 使用公式求斐波那契数列第n项值** 斐波那契数列是一个经典的数学序列,其公式为: \[ F_n=\\dfrac{\\left(\\frac{1+\\sqrt{5}}{2}\\right)^n-\\left(\\frac{1-\\sqrt{5}}{2}\\right)^n}{\\sqrt{5}} \] 要使用公式求斐波那契数列的第n项,首先需要计算phi和psi,它们是斐波那契数列中相邻两项的比值。然后计算分子和分母,最后将分子除以分母得到第n项的值。 **B. [NOIP2003 普及组] 乒乓球** 题目要求分析11分制和21分制对选手的不同影响。通过模拟比赛记录,计算华华在不同制式下的胜场数和负场数。 **解题思路** 1. 创建数组`win`存储胜负次数。 2. 逐行读取比赛信息,根据`win[i]`的值更新`w`和`l`。 3. 如果`w - l > 2` 或 `l - w > 2`,则输出当前比分。 4. 如果比赛分数达到11-10或21分,结束比赛并输出结果。 **C. 模拟算法** 模拟算法是解决这类问题的常用方法。通过模拟比赛过程,可以按照题目要求,逐步更新胜场数和负场数,最终得出结论。

正文

这是一个公式:

\[F_n=\dfrac{\left(\frac{1+\sqrt{5}}{2}\right)^n-\left(\frac{1-\sqrt{5}}{2}\right)^n}{\sqrt{5}} \]

根据大家的数学经验可以知道这是一个计算斐波那契数列的公式,那么假设我们不知道这是一个斐波纳契数列的公式,只知道他是一个简单的数学计算公式,该怎么求这个公式的值呢?答案就是需要使用模拟!而这篇博文,我们就来讨论一些简单的模拟题目,再教给大家一些做模拟题的方法。

Q1:使用公式求斐波那契数列第n项值

这是一个非常简单的模拟,可以直接使用C++头文件cmath中的库函数完成,这里我们可以看到题目中有两个比较难搞的东西,一个是:$$\sqrt{5} $$而另一个就是$${m}^{n} (m指的是前面的算式,分别是\left(\frac{1+\sqrt{5}}{2}\right)和\left(\frac{1-\sqrt{5}}{2}\right))$$

根号可以使用sqrt函数,而m的n次方可以使用pow函数(或者位运算),注意,这两个函数的返回值都是double类型的,所以最好使用double类型存储,而且pow函数会有精度误差,所以一定要谨慎使用。

接下来给大家看一下初步的代码:

#include<bits/stdc++.h>
using namespace std;
// 该函数用于计算斐波那契数列的第n项  
double fibonacci(int n) {  
	// 特判
    if(n <= 0) { 
        return 0;  
    }  
    // 模拟 
    double phi = (1 + sqrt(5)) / 2;
    double psi = (1 - sqrt(5)) / 2;
    double numerator = pow(phi, n) - pow(psi, n);  
    double denominator = sqrt(5); 
    return numerator / denominator;  
}  
  
int main() {  
    int n;  
    cin >> n; // 读入
    // 设置输出精度,以便更好地显示浮点数结果  
    cout << fixed << setprecision(2); // 这里我们输出两位小数  
    if (n >= 1) {  
        double res = fibonacci(n);  
        cout << "Fibonacci number at index " << n << " is: " << res << endl;  
    } else {  
        cout << "No answer" << endl;  
    }  
    return 0;  
}

输出一下,完全正确!

这里我们定义了一个函数fibonacci,该函数用于求斐波那契数列的第n项,在函数里面,我们定义了四个变量:phipsinumeratordenominator

phi求的是分数分子的左边部分(减号前的部分);
psi求的是分数分子的右半部分(减号后的部分);
numerator顾名思义是分子;
denominator顾名思义就是分母。
最后的返回值就是分数值(也就是分子除以分母)

接下来我们来看一看下一个问题。

Q2:[NOIP2003 普及组] 乒乓球

题目背景

国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中 \(11\) 分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白 \(11\) 分制和 \(21\) 分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

题目描述

华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 \(11\) 分制和 \(21\) 分制下,双方的比赛结果(截至记录末尾)。

比如现在有这么一份记录,(其中 \(\texttt W\) 表示华华获得一分,\(\texttt L\) 表示华华对手获得一分):

\(\texttt{WWWWWWWWWWWWWWWWWWWWWWLW}\)

\(11\) 分制下,此时比赛的结果是华华第一局 \(11\)\(0\) 获胜,第二局 \(11\)\(0\) 获胜,正在进行第三局,当前比分 \(1\)\(1\)。而在 \(21\) 分制下,此时比赛结果是华华第一局 \(21\)\(0\) 获胜,正在进行第二局,比分 \(2\)\(1\)。如果一局比赛刚开始,则此时比分为 \(0\)\(0\)。直到分差大于或者等于 \(2\),才一局结束。

你的程序就是要对于一系列比赛信息的输入(\(\texttt{WL}\) 形式),输出正确的结果。

输入格式

每个输入文件包含若干行字符串,字符串有大写的 \(\texttt W\)\(\texttt L\)\(\texttt E\) 组成。其中 \(\texttt E\) 表示比赛信息结束,程序应该忽略 \(\texttt E\) 之后的所有内容。

输出格式

输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是 \(11\) 分制下的结果,第二部分是 \(21\) 分制下的结果,两部分之间由一个空行分隔。

样例 #1

样例输入 #1

WWWWWWWWWWWWWWWWWWWW
WWLWE

样例输出 #1

11:0
11:0
1:1

21:0
2:1

提示

每行至多 \(25\) 个字母,最多有 \(2500\) 行。

(注:事实上有一个测试点有 \(2501\) 行数据。)

【题目来源】

NOIP 2003 普及组第一题

分析

这是一道很经典的签到模拟题,我们可以直接根据题意模拟:

#include<bits/stdc++.h>
using namespace std;
int win[114514];
int w, l;
int main() {
	char s;
	for(int i = 1; cin >> s && s != 'E'; ++ i) {
		if(s == 'W') win[i] = 1;
		else win[i] = 2;
	}
	for(int i = 1; ; ++ i) {
		if(win[i] == 1) ++ w;
		if(win[i] == 2) ++ l;
		if(win[i] == 0) {
			cout << w << ":" << l << endl << endl;
			break;
		}
		if(w - l >= 2 || l - w >= 2)
			if(w >= 11 || l >= 11) {
				cout << w << ":" << l << endl;
				w = 0;
				l = 0;
			}
	}
	w = 0;
	l = 0;
	for(int i = 1; ; ++ i) {
		if(win[i] == 1) ++ w;
		if(win[i] == 2) ++ l;
		if(win[i] == 0) {
			cout << w << ":" << l;
			break;
		}
		if(w - l >= 2 || l - w >= 2)
			if(w >= 21 || l >= 21) {
				cout << w << ":" << l << endl;
				w = 0;
				l = 0;
			}
	}
	return 0;
}

首先一定要开数组存储胜负次数,因为你不仅要存胜负的场数,还要存胜负的顺序,以此来排分数。其次分数差要大于2,这是因为正规乒乓球比赛,不仅分数要大于11(或21),两者分数相差也要大于2。如果比赛分数达到11-10,比赛会继续。直到一个人比另外一个人多两分。(如13-11)21分制同理,这里不再过多阐述。

其实这两道题目的模拟算是C++当中最简单的,接下来,我会再发表几篇文章用以阐述复杂的模拟算法。

与「C++」简单模拟相似的内容:

「C++」简单模拟

这是一个公式: \[F_n=\dfrac{\left(\frac{1+\sqrt{5}}{2}\right)^n-\left(\frac{1-\sqrt{5}}{2}\right)^n}{\sqrt{5}} \]根据大家的数学经验可以知道这是一个计算斐波那契数列的公式,那么假设我们不知道这是一个斐波

TensorRT c++部署onnx模型

在了解一些概念之前一直看不懂上交22年开源的TRTModule.cpp和.hpp,好在交爷写的足够模块化,可以配好环境开箱即用,移植很简单。最近稍微了解了神经网络的一些概念,又看了TensorRT的一些api,遂试着部署一下自己在MNIST手写数字数据集上训练的一个LeNet模型,识别率大概有98.

MongoDB基础知识梳理

简介 MongoDB 是由 C++ 编写的开源 NoSQL 和基于文档的数据库。MongoDB 提供了面向文档的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常流行的文档类型数据库。 MongoDB 是非关系型数据库当中功能最丰富,最像关系型数据库的

C++ STL 容器简单讲解

STL 简单讲解 网上有很多很好的资料可以参考 而直接看标准是最准确清晰的 vector stack queue / priority_queue deque array map / multimap set / multiset unordered_map unordered_set 关于指针和迭

用C++编写一个简单的发布者和订阅者

摘要:节点(Node)是通过 ROS 图进行通信的可执行进程。 本文分享自华为云社区《编写一个简单的发布者和订阅者》,作者: MAVER1CK 。 @[toc] 参考官方文档:Writing a simple publisher and subscriber (C++) 背景 节点(Node)是通过

华为云短信服务教你用C++实现Smgp协议

本文简单对SGIP协议进行了介绍,并尝试用C++实现协议栈,但实际商用发送短信往往更加复杂,可以选择华为云消息&短信服务通过HTTP协议接入。

C++ 递归与面向对象编程基础

C++ 递归 递归是一种使函数调用自身的技术。这种技术提供了一种将复杂问题分解为简单问题的方法,从而更容易解决问题。 递归可能有点难以理解。理解其工作原理的最佳方法是通过实验来尝试。 递归示例 将两个数字相加很容易做到,但将一系列数字相加就更复杂了。在下面的示例中,通过将其分解为将两个数字相加的简单

[转帖]「理解C++20协程原理」从Linux线程、线程与异步编程、协程与异步

协程不是系统级线程,很多时候协程被称为“轻量级线程”、“微线程”、“纤程(fiber)”等。简单来说可以认为协程是线程里不同的函数,这些函数之间可以相互快速切换。 协程和用户态线程非常接近,用户态线程之间的切换不需要陷入内核,但部分操作系统中用户态线程的切换需要内核态线程的辅助。 协程是编程语言(或

4.8 C++ Boost 应用JSON解析库

property_tree 是 Boost 库中的一个头文件库,用于处理和解析基于 XML、Json 或者 INFO 格式的数据。 property_tree 可以提供一个轻量级的、灵活的、基于二叉数的通用容器,可以处理包括简单值(如 int、float)和复杂数据结构(如结构体和嵌套容器)在内的各种数据类型。它可以解析数据文件到内存中,然后通过迭代器访问它们。在 Boost 库中,propert

C语言的简单学习

C语言是编译型语言,先编译再运行,通常用gcc进行编译,于是安装了Ubuntu操作系统。至于编辑器,VS Code也能用,先sudo apt install build-essential gdb,再在VS Code安装C/C++ extension,就可以进行开发了。 C语言程序都是 .c文件结尾