练7:模拟
欢迎大家订阅【蓝桥杯Python每日一练】 专栏,开启你的 Python数据结构与算法 学习之旅!
文章目录
- 1 模拟
- 2 例题详解
- 2.1 饮料换购
- 2.2 图像模糊
- 2.3 螺旋矩阵
1 模拟
①定义
模拟(Simulation)是计算机科学中的一种常见问题解决方法,指的是通过构造模型和模拟真实世界中的过程、现象或系统,来实现问题的解决。
在编程中,模拟通常涉及按照题目的描述,逐步模拟某一过程或状态的变化,并最终得出所需的结果。
②特点
- 根据规则逐步执行: 模拟问题的关键在于按照给定的规则或流程,逐步模拟某一事件的发生或系统的状态变化。每一步都要根据当前的状态决定下一步的操作。
- 状态变化: 模拟题通常要求追踪和管理系统中的状态。在模拟过程中,每次操作都会对系统的状态进行更新,直到达到最终目标或满足终止条件。
- 顺序操作: 模拟问题通常要求按照一定的顺序进行操作,按照题目要求的流程(如输入、处理、输出),并且每个操作都与前后的状态紧密关联。
- 简单规则的迭代实现: 虽然模拟题的规则可能较为简单,但需要通过多次迭代来完成任务。常见的操作如循环、状态更新、边界检查等。
- 避免复杂的数学计算或高深的算法: 模拟题不一定需要高级的数学知识或复杂的算法,更侧重于如何按步骤实现任务和维护状态。
③解题技巧
2 例题详解
2.1 饮料换购
题目地址:https://www.lanqiao.cn/problems/143/learning/
样例输入
100
样例输出
149
【题目分析】
①模拟思路: 题目要求模拟通过饮料瓶盖换购饮料的过程,每次以固定规则更新瓶盖和饮料总数,直到不满足换购条件。
②模拟特性:
直接按题意执行:
- 每次用 3 个瓶盖换 1 瓶饮料。
- 换购后更新剩余瓶盖数量。
- 循环结束条件为瓶盖数量不足 3。
模拟过程中需要追踪状态变化(当前瓶盖数量、已换购饮料总数)。
本题直接实现规则和状态更新,无需复杂算法,是典型的模拟问题。
代码示例
【示例1】
# n表示瓶盖的数量
n=int(input())
ans=n
# 法1
while True:
if n>=3:
# 把三个瓶盖换成一个饮料
n-=3
# 统计饮料的总和
ans+=1
# 更新瓶盖数量
n+=1
else:
break
print(ans)
【示例2】
# n表示瓶盖的数量
n=int(input())
ans=n
# 法2
while True:
if n>=3:
# n个瓶盖可以换n//3瓶饮料,还剩下n%3个瓶盖
# 统计饮料的总和
ans+=n//3
# 更新瓶盖数量
n+=1n//3+n%3
else:
break
print(ans)
运行结果
2.2 图像模糊
题目地址:https://www.lanqiao.cn/problems/550/learning/
样例输入
3 4
0 0 0 255
0 0 255 0
0 30 255 255
样例输出
0 42 85 127
5 60 116 170
7 90 132 191
【题目分析】
①模拟思路: 题目要求对矩阵中的每个元素,计算它与周围的元素的平均值,并将结果存入新的矩阵中。通过遍历矩阵并逐步计算每个位置的模糊值来完成任务。
②模拟特性:
a. 逐步按题意处理每个像素点:
- 确定当前像素的周围邻居范围。
- 累加有效邻居的值并计算平均。
- 更新模糊矩阵中的对应位置。
b. 符合模拟问题的两个关键特点:
- 状态更新:每个像素点的模糊值基于周围像素的状态计算。
- 逐步实现:直接模拟矩阵模糊的计算过程。
代码示例
n,m=map(int,input().split())
Map=[]
for i in range(n):
a=list(map(int,input().split()))
Map.append(a)
# 构建一个n行m列的二维list
ans=[[0]*m for i in range(n)]
for i in range(n):
for j in range(m):
# 遍历每个位置,求出模糊后的结果
# (i-1,j-1) (i-1,j) (i-1,j+1)
# (i,j-1) (i,j) (i,j+1)
# (i+1,j-1) (i+1,j) (i+1,j+1)
# 分别表示总和及个数
tot,cnt=0,0
# 遍历周围3*3区域
for delta_x in [-1,0,1]:
for delta_y in [-1,0,1]:
x=i+delta_x
y=j+delta_y
# 判断坐标(x,y)是否存在
if 0<=x<n and 0<=y<m:
tot+=Map[x][y]
cnt+=1
ans[i][j]=tot//cnt
for a in ans:
print(' '.join(map(str,a)))
【代码分析】
①输入数据
n, m = map(int, input().split())
这行代码读取矩阵的行数 n
和列数 m
,根据样例输入:
3 4
此时:
n = 3
(矩阵有 3 行)m = 4
(矩阵有 4 列)
②读取矩阵数据
Map = []
for i in range(n):
a = list(map(int, input().split()))
Map.append(a)
- 循环
n
次,每次读取一行的数字并存储到Map
中。 - 样例输入的数据分别是:
0 0 0 255 0 0 255 0 0 30 255 255
最终矩阵 Map
存储为一个二维列表:
Map = [
[0, 0, 0, 255],
[0, 0, 255, 0],
[0, 30, 255, 255]
]
③构建结果矩阵
ans = [[0] * m for _ in range(n)]
- 初始化一个大小为
n × m
的二维列表ans
,所有元素都为 0,用来存储模糊后的结果。 - 初始状态为:
ans = [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
④模糊处理
外层双循环:
for i in range(n): # 遍历矩阵的每一行
for j in range(m): # 遍历矩阵的每一列
这里 (i, j)
是当前正在处理的矩阵位置。
⑤计算模糊值
对于位置 (i, j)
,计算其周围 3×3 区域的模糊值。
【遍历 3×3 区域】
for delta_x in [-1, 0, 1]: # 遍历相对于 i 的偏移
for delta_y in [-1, 0, 1]: # 遍历相对于 j 的偏移
(delta_x, delta_y)
是偏移量,表示当前位置 (i, j)
的邻居:
delta_x = -1
表示上方一行delta_x = 0
表示当前行delta_x = 1
表示下方一行
【计算邻居位置】
x = i + delta_x # 计算邻居的行索引
y = j + delta_y # 计算邻居的列索引
【检查边界合法性】
if 0 <= x < n and 0 <= y < m:
检查 (x, y)
是否在矩阵范围内:
- 行号
x
必须在[0, n-1]
范围内。 - 列号
y
必须在[0, m-1]
范围内。 - 如果邻居超出矩阵范围,则忽略。
⑥累加值和计数
对于合法的 (x, y)
:
tot += Map[x][y] # 累加邻居的值
cnt += 1 # 统计有效邻居的数量
tot
是邻居元素的总和,cnt
是有效邻居的数量。
⑦平均值计算
计算模糊后的值并存入结果矩阵:
ans[i][j] = tot // cnt
tot // cnt
是总和除以有效数量,取整。
⑧输出结果
for a in ans:
print(' '.join(map(str, a)))
- 遍历
ans
矩阵的每一行,将其转换为字符串并打印。
运行结果
2.3 螺旋矩阵
题目地址:https://www.lanqiao.cn/problems/156/learning/
样例输入
4 5
2 2
样例输出
15
【题目分析】
①模拟思路::按照螺旋顺序填充矩阵,逐步将值填入每个位置,最终输出目标位置的值。
②模拟特性:
a. 按题意执行:
- 从左上角开始,按右、下、左、上的方向依次填充矩阵。
- 边界条件控制填充的范围。
b. 需要状态维护:
- 当前填充值。
- 当前方向(右、下、左、上)的变化规则。
- 已填充的位置状态避免重复覆盖。
c. 模拟问题的核心是动态更新矩阵状态和循环实现填充过程。
代码示例
n,m=map(int,input().split())
r,c=map(int,input().split())
# 初始化矩阵
ans=[[0]*m for i in range(n)]
# 当前坐标
x,y=0,0
# 当前存放的值
value=1
ans[x][y]=value
# 填充螺旋矩阵
while value<n*m:
# 往右走(x,y+1)
while y+1<m and ans[x][y+1]==0:
value+=1
y+=1
ans[x][y]=value
# 往下走(x+1,y)
while x+1<n and ans[x+1][y]==0:
value+=1
x+=1
ans[x][y]=value
# 往左走(x,y-1)
while y-1>=0 and ans[x][y-1]==0:
value+=1
y-=1
ans[x][y]=value
# 往上走(x-1,y)
while x-1>=0 and ans[x-1][y]==0:
value+=1
x-=1
ans[x][y]=value
# 输出目标位置的值
print(ans[r-1][c-1])
【代码分析】
①输入部分
n, m = map(int, input().split()) # 矩阵大小,n 行 m 列
r, c = map(int, input().split()) # 目标位置 (r, c)
- 示例输入:
4 5
表示矩阵大小为 ( 4 * 5 )。 - 示例输入:
2 2
表示目标位置为矩阵第 2 行第 2 列。
②初始化矩阵
ans = [[0] * m for i in range(n)] # 创建一个 n 行 m 列的矩阵,初始值为 0
构造一个 ( 4 * 5 ) 的矩阵:
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
③设置初始位置和填充值
x, y = 0, 0 # 初始位置在左上角
value = 1 # 初始值为 1
ans[x][y] = value
设置矩阵左上角 ((0,0)) 为 1:
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
④填充矩阵(螺旋过程)
- 主循环:当
value < n * m
时继续填充。 - 方向顺序:右 → 下 → 左 → 上。
a. 往右填充:
while y + 1 < m and ans[x][y + 1] == 0:
value += 1
y += 1
ans[x][y] = value
- 持续向右填充,直到无法前进(列超出范围或右侧已填充)。
- y 从 0 -> 4,对应矩阵:
1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2. 往下填充:
while x + 1 < n and ans[x + 1][y] == 0:
value += 1
x += 1
ans[x][y] = value
- 持续向下填充,直到无法前进。
- x 从 0 -> 3,对应矩阵:
1 2 3 4 5
0 0 0 0 6
0 0 0 0 7
0 0 0 0 8
c. 往左填充:
while y - 1 >= 0 and ans[x][y - 1] == 0:
value += 1
y -= 1
ans[x][y] = value
- 持续向左填充,直到无法前进。
- y 从 4 -> 0,对应矩阵:
1 2 3 4 5
0 0 0 0 6
0 0 0 0 7
12 11 10 9 8
d. 往上填充:
while x - 1 >= 0 and ans[x - 1][y] == 0:
value += 1
x -= 1
ans[x][y] = value
- 持续向上填充,直到无法前进。
- x 从 3 -> 1,对应矩阵:
1 2 3 4 5
14 0 0 0 6
13 0 0 0 7
12 11 10 9 8
e. 再次往右:
填充右侧的空格:
1 2 3 4 5
14 15 16 17 6
13 0 0 0 7
12 11 10 9 8
以此类推……
最终矩阵:
1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8
⑤目标值:
print(ans[r-1][c-1])
- ( r = 2, c = 2 ),对应矩阵的索引为 ( (1, 1) )。
- 值为
15
。
运行结果