PAT乙级_1073 多选题常见计分法_Python_AC解法_含疑难点
注意事项:
因为笔者的编程水平以自学为主,代码结构可能比较混乱、变量命名可能不够规范。
文章中的AC解法不一定最优,并且包含笔者强烈的个人风格,不喜勿喷,但欢迎在评论中理性讨论或者给出提升建议。
文章中提到的疑难点仅为个人在刷题过程中所遇到的情况,如有读者存在其他疑难点,欢迎在评论中加以补充,笔者会尽量将其加入到文章内容中。
合集:
PAT乙级_合集_Python_AC解法
题目:
1073 多选题常见计分法
题目描述:
批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数;如果考生选择了任何一个错误的选项,则不能得分。本题就请你写个程序帮助老师批改多选题,并且指出哪道题的哪个选项错的人最多。
输入格式:
输入在第一行给出两个正整数 N(≤1000)和 M(≤100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……)
,按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。另一方面,题目也保证选中的选项个数
是正整数。
输出格式:
按照输入的顺序给出每个学生的得分,每个分数占一行,输出小数点后 1 位。最后输出错得最多的题目选项的信息,格式为:错误次数 题目编号(题目按照输入的顺序从1开始编号)-选项号
。如果有并列,则每行一个选项,按题目编号递增顺序输出;再并列则按选项号递增顺序输出。行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple
。
输入样例1:
3 4
3 4 2 a c
2 5 1 b
5 3 2 b c
1 5 4 a b d e
(2 a c) (3 b d e) (2 a c) (3 a b e)
(2 a c) (1 b) (2 a b) (4 a b d e)
(2 b d) (1 e) (1 c) (4 a b c d)
输出样例1:
3.5
6.0
2.5
2 2-e
2 3-a
2 3-b
输入样例2:
2 2
3 4 2 a c
2 5 1 b
(2 a c) (1 b)
(2 a c) (1 b)
输出样例2:
5.0
5.0
Too simple
代码限制:
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
AC解法:
# 获取首行输入数据
n, m = map(int, input().split())# 读取题目数据
cor = {} # 用于存储题目数据
incor = {} # 用于存储各题的错误情况
for i in range(m): # 遍历题目question = input().split() # 读取该行题目数据cor[i+1] = (question[:3], set(question[3:]))# 以遍历的下标为题号,并当作题目字典的键,切分题目的分值选项数与正确选项,再以元组形式组合存储为字典对应的值incor[i+1] = {chr(key + 97): 0 for key in range(int(question[1]))}# 初始化错题情况字典,以题号当作键,嵌套选项字典为错题字典的值;选项字典中键为所该题所有选项,值默认为 0# 读取作答数据并同步输出分数
for _ in range(n): # 遍历作答answer = input().split(') ') # 分割该行作答数据score = 0 # 初始化得分为 0for j in range(m): # 根据题号遍历flag = f = True # 初始化两个标记值为 True , flag 用于标记是否全对, f 用于表示是否部分对但无错options_ans = set(answer[j][3::2]) # 根据切分的结果读取该题的作答选项options_cor = cor[j+1][1] # 拿取该题的正确选项for oa in options_ans: # 遍历作答选项if oa not in options_cor: # 若该选项不在正确选项中flag = f = False # 全对标记 flag 与部分对但无错标记 f 均置为 Falseincor[j+1][oa] += 1 # 对应的该题该选项错题情况计数 +1for oc in options_cor: # 遍历正确答案if oc not in options_ans: # 若该选项不在作答选项中flag = False # 全对标记 flag 置为 Falseincor[j+1][oc] += 1 # 对应的该题该选项错题情况计数 +1if flag and f: # 若 flag 和 f 两个标记值均为 True,即该题作答全对score += int(cor[j+1][0][0]) # 获得该题所有得分elif not flag and f: # 若全队标记 flag 为 False 但无错标记 f 为 True,即部分对但无错score += int(cor[j+1][0][0]) * 0.5 # 获得该题一半分数print(f"{score:.1f}") # 按格式要求输出该作答的总得分# 整理错误情况
cnt = {} # 创建次数空字典
for k in range(m): # 遍历题目for t in incor[k+1]: # 遍历该题各选项的错误情况tmp = incor[k+1][t] # 取出该题该选项的错误次数if tmp not in cnt: # 若该次数不在 cnt 中cnt[tmp] = [f"{tmp} {k+1}-{t}"] # 以次数为键,按格式要求所拼接的字符串以列表形式为值else: # 该次数已存在 cnt 中cnt[tmp].append(f"{tmp} {k+1}-{t}") # 该次数的列表中添加拼接后的字符串# 根据不同情况按格式要求输出错误结果
mc = max(cnt) # 获取最大的错误次数
if mc == 0: # 若最大错误次数为 0 ,即所有作答均全对print('Too simple') # 按格式要求输出全队结果
else: # 最大错误次数大于 0for res in cnt[mc]: # 遍历该次数中出现的题目选项字符串print(res) # 因为存储时已经按格式要求拼接,直接输出该字符串即可
题目解读:
本题描述比较易懂。
先依次读取输入的题目数据和作答数据,再根据作答情况计算出该作答的总分并按格式要求输出,最后统计错误次数最多的选项数据按格式要求输出。
疑难点:
其他注意事项
1、
本题无疑难点,但是AC解法中对于数据的存储存在多层嵌套,需要仔细理清嵌套关系,在理解题意后避免出错即可。