🔒 答案已锁定

📖 答案解析 — 智传民韵(民族文化) — 困难2

算法应用主题赛 · Python · 共 14 题(5单选+5多选+4编程)· 满分 100 分

第 1 题 单选题 2 分
壮族壮锦工艺中,绣娘按照编号顺序排列了n幅壮锦图案(编号从小到大有序排列)。现在需要查找编号为target的壮锦图案是否在排列中。使用二分查找算法,每次比较后搜索范围的变化方式是?
A. 每次将搜索范围缩小为原来的一半
B. 每次将搜索范围减少一个元素
C. 每次随机选取一个位置进行比较
D. 每次从第一个元素开始逐一比较
✅ 正确答案:A
💡 考点解析:二分查找算法的基本思想(每次将搜索范围缩小一半,时间复杂度O(log n))
第 2 题 单选题 2 分
彝族火把节要按火把燃烧时长从小到大排列。对列表[45, 12, 78, 33, 56]进行冒泡排序(升序),第一轮冒泡结束后的序列是?
A. [12, 33, 45, 56, 78]
B. [12, 45, 33, 56, 78]
C. [12, 33, 45, 78, 56]
D. [12, 45, 78, 33, 56]
✅ 正确答案:B
💡 考点解析:冒泡排序的过程(第一轮冒泡将最大值78移到最后,依次比较相邻元素并交换,结果:[12, 45, 33, 56, 78])
第 3 题 单选题 2 分
藏族唐卡绘制中,画师将整幅唐卡分解为若干小区域分别绘制,最后组合成完整图案。这种"将大问题分解为相互重叠的子问题,通过子问题的最优解构造原问题的最优解"的算法思想属于动态规划。动态规划的核心特征是?
A. 每次选择当前看起来最好的方案
B. 问题的解包含其子问题的最优解(最优子结构)
C. 将所有可能的解全部列举出来逐一验证
D. 按照固定公式一步步递推计算
✅ 正确答案:B
💡 考点解析:动态规划的核心概念(最优子结构:问题的最优解包含子问题的最优解)
第 4 题 单选题 2 分
在那达慕大会的赛马排位问题中,需要尝试多种马匹出场顺序方案,如果当前方案不满足条件,就回退到上一步尝试其他方案。这种"试探-回退-再试探"的算法思想被称为?
A. 贪心算法
B. 动态规划
C. 回溯算法
D. 二分查找
✅ 正确答案:C
💡 考点解析:回溯算法的基本思想(逐步试探,遇到不满足条件时回退到上一步尝试其他可能性)
第 5 题 单选题 2 分
傣族泼水节活动中,人们排成一队依次取水。这种"先到先取、后到后取"的排队规则,在数据结构中体现为?
A. 栈(先进后出)
B. 队列(先进先出)
C. 树(层次结构)
D. 图(网状结构)
✅ 正确答案:B
💡 考点解析:队列数据结构的概念(FIFO:先进先出,符合排队场景)
第 6 题 多选题 4 分
在整理各民族传统节日数据时,常用排序算法进行数据处理。关于冒泡排序、选择排序和插入排序,以下说法正确的有?
A. 冒泡排序在每一轮中通过相邻元素两两比较交换,将最大(或最小)元素"冒泡"到末端
B. 选择排序在每一轮中从未排序部分选出最小(或最大)元素,放到已排序部分的末尾
C. 三种排序算法的最坏时间复杂度均为O(n²)
D. 插入排序在数据基本有序时效率较高,最优时间复杂度可达O(n)
✅ 正确答案:ABCD
💡 考点解析:排序算法的特点与复杂度(冒泡、选择、插入的基本思想及时间复杂度对比)
第 7 题 多选题 4 分
在民族村寨的地图导航中,常使用广度优先搜索(BFS)和深度优先搜索(DFS)。以下关于BFS和DFS的说法,正确的有?
A. BFS使用队列实现,按层逐层遍历,适合找最短路径
B. DFS使用栈(或递归)实现,沿着一条路径深入到底再回溯
C. BFS一定能找到从起点到终点的最短路径(在无权图中)
D. BFS通常比DFS占用更多的内存空间
✅ 正确答案:ABCD
💡 考点解析:BFS与DFS的实现方式、特点及应用场景对比
第 8 题 多选题 4 分
在"蒙古族物资分配"问题中,贪心算法和动态规划都可以用来求解最优化问题。以下关于两者区别的说法,正确的有?
A. 贪心算法每一步选择局部最优,不一定能得到全局最优解
B. 动态规划通过保存子问题的解来避免重复计算,保证得到全局最优解
C. 对于0-1背包问题,贪心算法不能保证得到最优解,而动态规划可以
D. 贪心算法通常比动态规划的时间复杂度更低
✅ 正确答案:ABCD
💡 考点解析:动态规划与贪心算法的区别(局部最优vs全局最优、子问题复用、适用范围、复杂度对比)
第 9 题 多选题 4 分
在Python中处理民族纹样图案时,经常需要复制列表。关于列表的浅拷贝(shallow copy)和深拷贝(deep copy),以下说法正确的有?
A. list2 = list1[:] 创建的是浅拷贝,修改list2中的不可变元素不会影响list1
B. 如果列表中包含嵌套列表,浅拷贝只复制了嵌套列表的引用
C. 使用copy.deepcopy()可以递归复制所有嵌套对象,修改拷贝后的嵌套列表不会影响原列表
D. list2 = list1 不是拷贝,而是让list2和list1指向同一个列表对象
✅ 正确答案:ABCD
💡 考点解析:列表的赋值、浅拷贝与深拷贝的区别
第 10 题 多选题 4 分
分析民族算法程序的效率时,需要评估时间复杂度和空间复杂度。以下关于算法复杂度的说法,正确的有?
A. 时间复杂度O(1)表示算法的执行时间与输入规模无关
B. 二分查找的时间复杂度为O(log n),优于顺序查找的O(n)
C. 递归算法由于调用栈的存在,除了时间复杂度外还需要考虑额外的空间复杂度
D. 空间复杂度分析包括算法执行时所需的辅助空间(不包括存储输入数据本身的空间)
✅ 正确答案:ABCD
💡 考点解析:算法时间复杂度和空间复杂度的概念与分析
第 11 题 编程操作题 15 分

题目描述:
蒙古族牧民在草原上游牧,草原可以看作一个m行n列的网格。网格中每个位置可能是:
- 0 表示草地(可以通过)
- 1 表示戈壁或山地(不可通过)
牧民从起点位置(start_x, start_y)出发,需要到达终点位置(end_x, end_y)。牧民每次只能向上下左右四个方向之一移动一格,且不能移动到网格外或戈壁/山地上。
请编写程序,计算从起点到终点的最短步数。如果无法到达终点,输出-1。
注意:行列索引均从0开始计数。

输入格式:
第一行输入两个整数m和n,表示网格的行数和列数,用空格分隔(1 ≤ m, n ≤ 100)。
接下来m行,每行输入n个整数(0或1),表示网格地图。
最后一行输入四个整数start_x, start_y, end_x, end_y,分别表示起点和终点的行列坐标,用空格分隔。

输出格式:
输出一个整数,表示从起点到终点的最短步数。若无法到达则输出-1。

示例输入:

5 5
0 0 0 1 0
1 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 0 0
0 0 4 4

示例输出:

8
说明:从(0,0)到(4,4),需要绕过障碍,最短路径需要8步。
✅ 参考答案:
📖 参考代码
from collections import deque
m, n = map(int, input().split())
grid = []
for _ in range(m):
    grid.append(list(map(int, input().split())))
start_x, start_y, end_x, end_y = map(int, input().split())
# 如果起点或终点本身是障碍,无法到达
if grid[start_x][start_y] == 1 or grid[end_x][end_y] == 1:
    print(-1)
else:
    # BFS
    # 四个方向:上、下、左、右
    dx = [-1, 1, 0, 0]
    dy = [0, 0, -1, 1]
    # visited数组记录是否访问过
    visited = [[False] * n for _ in range(m)]
    visited[start_x][start_y] = True
    # 队列中存储 (x, y, 步数)
    queue = deque()
    queue.append((start_x, start_y, 0))
    answer = -1
    while queue:
        x, y, steps = queue.popleft()
        # 到达终点
        if x == end_x and y == end_y:
            answer = steps
            break
        # 向四个方向扩展
        for k in range(4):
            nx = x + dx[k]
            ny = y + dy[k]
            # 检查边界、是否可通行、是否已访问
            if 0 <= nx < m and 0 <= ny < n:
                if grid[nx][ny] == 0 and not visited[nx][ny]:
                    visited[nx][ny] = True
                    queue.append((nx, ny, steps + 1))
    print(answer)
第 12 题 编程操作题 15 分

题目描述:
傣族泼水节上有n个水池,每个水池有一个容量c_i(单位:升)和一个单位快乐值h_i。每向第i个水池加入1升水,就能获得h_i点快乐值,但加入的水量不能超过该水池的容量c_i。现在总共有M升水可以分配。
请使用贪心策略(优先向单位快乐值最高的水池加水;若单位快乐值相同,优先向容量大的水池加水),计算能获得的最大总快乐值。

输入格式:
第一行输入两个整数n和M,表示水池数量和总水量,用空格分隔(1 ≤ n ≤ 100,1 ≤ M ≤ 10000)。
接下来n行,每行输入两个整数c_i和h_i,分别表示第i个水池的容量和单位快乐值(1 ≤ c_i ≤ 1000,1 ≤ h_i ≤ 100)。

输出格式:
第一行输出一个整数,表示最大总快乐值。
接下来若干行,每行输出一个水池的分配信息:"水池i: 加入X升",按加水顺序输出。若某个水池没有被分配到水,则不输出。

示例输入:

4 50
20 3
30 2
15 4
25 1

示例输出:

150
水池3: 加入15升
水池1: 加入20升
水池2: 加入15升
说明:
- 单位快乐值:水池3=4最高,水池1=3次之,水池2=2,水池4=1最低。
- 先向水池3加满15升(得60快乐),再向水池1加满20升(得60快乐),剩余15升加入水池2(得30快乐)。
- 水池4未获得水。
- 总快乐 = 15×4 + 20×3 + 15×2 = 60 + 60 + 30 = 150。
✅ 参考答案:
📖 参考代码
n, M = map(int, input().split())
pools = []
for i in range(n):
    c, h = map(int, input().split())
    pools.append([i + 1, c, h])
# 按单位快乐值降序排序;单位快乐值相同按容量降序
pools.sort(key=lambda x: (-x[2], -x[1]))
remaining = M
total_joy = 0
results = []
for idx, cap, joy in pools:
    if remaining <= 0:
        break
    if cap <= remaining:
        # 加满该水池
        results.append((idx, cap))
        total_joy += cap * joy
        remaining -= cap
    else:
        # 只能加入部分水
        results.append((idx, remaining))
        total_joy += remaining * joy
        remaining = 0
print(total_joy)
for idx, amount in results:
    print(f"水池{idx}: 加入{amount}升")
第 13 题 编程操作题 20 分

题目描述:
苗族银匠有一批精美的银饰,每件银饰有其重量w_i(克)和艺术价值v_i。银匠准备将这些银饰装入展示箱,展示箱的最大承重为W(克),总重量不能超过W。每件银饰只能选择装入或不装入(不可分割)。
请编写程序,使用0-1背包动态规划算法,计算在不超过最大承重的前提下,能够获得的最大总艺术价值。

输入格式:
第一行输入两个整数n和W,表示银饰数量和展示箱最大承重,用空格分隔(1 ≤ n ≤ 100,1 ≤ W ≤ 1000)。
接下来n行,每行输入两个整数w_i和v_i,表示第i件银饰的重量和艺术价值(1 ≤ w_i ≤ 200,1 ≤ v_i ≤ 1000)。

输出格式:
第一行输出一个整数,表示最大总艺术价值。
第二行输出被选中的银饰编号(从1开始),按编号升序排列,用空格分隔。若有多组最优解,输出其中任意一组即可。

示例输入:

4 10
2 3
3 4
4 5
5 8

示例输出:

12
2 4
说明:选择第2件(重量3,价值4)和第4件(重量5,价值8),总重量8≤10,总价值12,为最优解。
✅ 参考答案:
📖 参考代码
n, W = map(int, input().split())
weights = [0]
values = [0]
for i in range(1, n + 1):
    w, v = map(int, input().split())
    weights.append(w)
    values.append(v)
# dp[i][j]: 考虑前i件银饰,总重量不超过j时的最大价值
dp = [[0] * (W + 1) for _ in range(n + 1)]
# 记录选择路径:choice[i][j] 表示在考虑前i件、容量为j时是否选择了第i件
choice = [[False] * (W + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
    for j in range(1, W + 1):
        # 不选第i件
        dp[i][j] = dp[i - 1][j]
        # 可以选第i件
        if j >= weights[i]:
            if dp[i - 1][j - weights[i]] + values[i] > dp[i][j]:
                dp[i][j] = dp[i - 1][j - weights[i]] + values[i]
                choice[i][j] = True
print(dp[n][W])
# 回溯找出被选中的银饰编号
selected = []
j = W
for i in range(n, 0, -1):
    if choice[i][j]:
        selected.append(i)
        j -= weights[i]
selected.sort()
print(' '.join(map(str, selected)))
第 14 题 编程操作题 20 分

题目描述:
藏族唐卡画师在一块m行n列的画布上绘制图案。画布上的每个格子用数字表示颜色(相同的数字代表同一种颜色,0表示未上色区域,不计入连通区域)。如果两个同色格子上下左右相邻(四连通),则它们属于同一个连通颜色区域。
请编写程序,使用深度优先搜索(DFS)或广度优先搜索(BFS),统计画布中一共有多少个连通颜色区域(值为0的格子不算颜色区域)。

输入格式:
第一行输入两个整数m和n,表示画布的行数和列数,用空格分隔(1 ≤ m, n ≤ 100)。
接下来m行,每行输入n个整数(非负整数,范围0~9),表示每个格子的颜色值。

输出格式:
第一行输出一个整数,表示连通颜色区域的总数。
接下来每行输出一个连通区域的信息:颜色值和该颜色连通区域的格子数,格式为"颜色X: Y个格子"。按颜色值从小到大的顺序输出;同一颜色可能有多个连通区域,每个独立区域单独计算。

示例输入:

5 5
1 1 1 2 2
1 1 0 2 0
0 0 3 0 0
0 0 0 2 2
1 1 0 2 2

示例输出:

5
颜色1: 5个格子
颜色1: 2个格子
颜色2: 3个格子
颜色2: 4个格子
颜色3: 1个格子
说明:画布中有5个连通颜色区域:
- 左上角的5个1((0,0)(0,1)(0,2)(1,0)(1,1)形成一个连通区域)
- 左下角的2个1((4,0)(4,1)是另一个独立的连通区域)
- 右上角的3个2((0,3)(0,4)(1,3)形成一个连通区域)
- 右下角的4个2((3,3)(3,4)(4,3)(4,4)形成另一个连通区域)
- 中间的1个3((2,2)单独一个区域)
✅ 参考答案:
📖 参考代码
import sys
sys.setrecursionlimit(1000000)
m, n = map(int, input().split())
grid = []
for _ in range(m):
    grid.append(list(map(int, input().split())))
visited = [[False] * n for _ in range(m)]
# 四个方向:上、下、左、右
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
def dfs(x, y, color):
    """从(x,y)出发DFS搜索同色连通区域,返回该区域的格子数"""
    count = 1
    visited[x][y] = True
    for k in range(4):
        nx = x + dx[k]
        ny = y + dy[k]
        if 0 <= nx < m and 0 <= ny < n:
            if not visited[nx][ny] and grid[nx][ny] == color:
                count += dfs(nx, ny, color)
    return count
# BFS版本(备选)
from collections import deque
def bfs(start_x, start_y, color):
    """从(start_x, start_y)出发BFS搜索同色连通区域,返回该区域的格子数"""
    count = 0
    queue = deque()
    queue.append((start_x, start_y))
    visited[start_x][start_y] = True
    while queue:
        x, y = queue.popleft()
        count += 1
        for k in range(4):
            nx = x + dx[k]
            ny = y + dy[k]
            if 0 <= nx < m and 0 <= ny < n:
                if not visited[nx][ny] and grid[nx][ny] == color:
                    visited[nx][ny] = True
                    queue.append((nx, ny))
    return count
# 遍历整个画布,找出所有连通区域
regions = []  # 存储 (颜色, 格子数)
for i in range(m):
    for j in range(n):
        if grid[i][j] != 0 and not visited[i][j]:
            # 使用DFS
            # region_size = dfs(i, j, grid[i][j])
            # 或使用BFS(任选一种,效果相同)
            region_size = bfs(i, j, grid[i][j])
            regions.append((grid[i][j], region_size))
# 先按颜色值排序,相同颜色按发现的先后顺序(即原始顺序)
regions.sort(key=lambda x: x[0])
print(len(regions))
for color, size in regions:
    print(f"颜色{color}: {size}个格子")