1 什么是模拟
首先,我们来深入理解“模拟”这一词汇在广义上的含义。在百度等搜索引擎中,“模拟”常被解释为:
通过构建或复现某种情境、过程或系统,以预测或展示其行为的方法。
那么,当我们将这一概念应用于算法领域时,模拟算法便应运而生:
简而言之,模拟算法即是遵循题目所描述的具体步骤,通过编程手段一一执行这些步骤,从而忠实地模拟出题目要求的过程,并最终得到相应的结果。
2 模拟的优缺点
2.1 模拟算法的魅力:
模拟算法的魅力在于它直接反映了人类面对问题时的最原始、最直观的思维方式。
比如,当题目要求我们给每个数加上一个特定的值A时,我们不会立即去寻找复杂的数学公式或算法优化,而是直接遍历每个数,逐一加上A。同样,如果题目要求我们从一组数中删除最小的数,我们也会自然而然地想到先找到这个最小的数,然后再将其从集合中移除。
2.2 优点
直观性:模拟算法直接反映了问题的实际操作流程,使得理解和实现都变得相对简单。
灵活性:对于不同的问题,可以通过调整模拟的步骤来适应,具有很好的通用性和灵活性。
2.3 缺点
效率可能不高:对于一些复杂的问题,如果直接模拟,可能会涉及大量的计算步骤,导致算法效率较低。(时空复杂度过高)
2.4 总结:
这种直接、朴素的方法虽然可能在某些情况下不是最高效的,但它却因其简单易懂、易于实现而备受青睐。在解决复杂问题或进行算法设计时,模拟算法往往是一个很好的起点,它能帮助我们更好地理解问题,并为后续的优化提供基础。
3 问题实例
3.1 成绩统计
题目描述
小蓝给学生们组织了一场考试,卷面总分为 100 分,每个学生的得分都是一个 0 到 100 的整数。
如果得分至少是 60 分,则称为及格。如果得分至少为 85 分,则称为优秀。
请计算及格率和优秀率,用百分数表示,百分号前的部分四舍五入保留整 数。
输入描述
输入的第一行包含一个整数 𝑛 (1≤𝑛≤
)n (1≤n≤
),表示考试人数。
接下来 𝑛n 行,每行包含一个 0 至 100 的整数,表示一个学生的得分。
输出描述
输出两行,每行一个百分数,分别表示及格率和优秀率。百分号前的部分 四舍五入保留整数。
示例:
输入
7 80 92 56 74 88 100 0
输出
71% 43%
思路:
直接遍历所有成绩数据,分别统计及格和优秀的同学数量,然后计算百分比。注意输出时要四舍五入保留整数。
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n; // 读取学生数量
int pass = 0, excellent = 0;
for (int i = 0; i < n; i++)
{
int score;
cin >> score; // 读取每个学生的成绩
if (score >= 60)
pass++;
if (score >= 85)
excellent++;
}
int passRate = (pass * 100 + n / 2) / n; // 四舍五入
int excellentRate = (excellent * 100 + n / 2) / n; // 四舍五入
cout << passRate << '%' << endl;
cout << excellentRate << '%';
return 0;
}
3.2 门牌制作
题目描述
小蓝要为一条街的住户制作门牌号。
这条街一共有 2020 位住户,门牌号从 1 到 2020 编号。
小蓝制作门牌的方法是先制作 0 到 9 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌 1017 需要依次粘贴字符 1、0、1、7,即需要 1 个字符 0,2 个字符 1,1 个字符 7。
请问要制作所有的 1 到 2020 号门牌,总共需要多少个字符 2?
思路:
遍历1到2020的每个数字,对每个数字使用取模和整除操作来分解其每一位,并判断该位是否为'2'。如果是,则计数器加1。最后输出总和。
代码:
#include <bits/stdc++.h>
using namespace std;
int countTwos(int a) // 判断一个数字中有多少个'2'
{
int num = 0;
while (a > 0)
{
int x = a % 10;
if (x == 2)
num++;
a = a / 10;
}
return num;
}
int main()
{
int sum = 0;
for (int i = 1; i <= 2020; i++)
{
sum += countTwos(i); // 依次求和
}
cout << sum;
return 0;
}