PAT乙级_1073 多选题常见计分法_Python_AC解法_含疑难点

发布于:2025-08-16 ⋅ 阅读:(36) ⋅ 点赞:(0)

注意事项:

       因为笔者的编程水平以自学为主,代码结构可能比较混乱、变量命名可能不够规范。

       文章中的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  # 初始化得分为 0
    for 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 均置为 False
                incor[j+1][oa] += 1  # 对应的该题该选项错题情况计数 +1
        for oc in options_cor:  # 遍历正确答案
            if oc not in options_ans:  # 若该选项不在作答选项中
                flag = False  # 全对标记 flag 置为 False
                incor[j+1][oc] += 1  # 对应的该题该选项错题情况计数 +1
        if 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:  # 最大错误次数大于 0
    for res in cnt[mc]:  # 遍历该次数中出现的题目选项字符串
        print(res)  # 因为存储时已经按格式要求拼接,直接输出该字符串即可

题目解读:

       本题描述比较易懂。

       先依次读取输入的题目数据和作答数据,再根据作答情况计算出该作答的总分并按格式要求输出,最后统计错误次数最多的选项数据按格式要求输出。

疑难点: 

其他注意事项

1、

       本题无疑难点,但是AC解法中对于数据的存储存在多层嵌套,需要仔细理清嵌套关系,在理解题意后避免出错即可。


网站公告

今日签到

点亮在社区的每一天
去签到