PAT乙级 1073多选题常见计分法 坑题意解读 测试点3/4分析解决

1073 多选题常见计分法 (20分)

批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 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

题意太坑了,输出错得最多的题目选项的信息,这个错的最多不是某个题的学生错误数最大,而是学生的选项错误数最大。

例如某个题答案bc,甲学生选择abc,乙学生选择bc,丙学生选择b,丁学生选择了abc。那么对于该题,题中所指的错误数不是3(甲丙丁做错了),而是2,甲丙丁三个人的选项放在一起,他们共计错选了2次a、漏选了1次c,2就是该题最大选项错误数。

漏选和错选都算错误,每个题的都有自己的最大错误数,它们之中的最大值就是需要输出的错误次数,测试点3和4就是这个问题。

最坑的是,它给的样例还完美符合把最大错误数当成每道题错误数的最大,我(lll¬ω¬)

在下就是一开始理解错了题意,参考网上代码才明白,以下代码是我在错误题意上改的,完全没必要和在下写的一样那么乱、那么冗杂,凑活当当参考吧,尽量注释清楚。实在不想重做了,心力憔悴啊/(ㄒoㄒ)/~~

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string>

using namespace std;

struct problem {//每道题的信息
    double score;//分数
    int sumchoice;//一共几个选项
    int rightchoice;//正确选项的数量
    string right;//正确选项的字符串,去除了空格,如:abc
};

struct wrong {//每道题的错误信息
    int id;//该题的题号
    int sum = 0;//学生做错了几次,理解错题意,现在可以删了
    int choice[5] = {0};//每道选项做错了几次,下标0~5对应abcde
};

int cmp(struct wrong a, struct wrong b) {//理解错题意用的排序,可以删了
    return (a.sum != b.sum) ? a.sum > b.sum : a.id < b.id;
}

int main() {
    int n, m;
    cin >> n >> m;
    problem prs[m];//每道题
    wrong ps[m];//每道题错误信息
    int flag = 0;//记录最大的选项错误次数
    for(int i = 1; i <= m; i++) {
        cin >> prs[i - 1].score;
        cin >> prs[i - 1].sumchoice;
        cin >> prs[i - 1].rightchoice;
        ps[i - 1].id = i;
        for(int a = 1; a <= prs[i - 1].rightchoice; a++) {
            char ch;
            cin >> ch;//这样输入,空格就省略了
            prs[i - 1].right += ch;
        }
    }
    double everyscore[n] = {0};//每个学生的分数
    for(int i = 1; i <= n; i++) {
        for(int a = 1; a <= m; a++) {
            char ch;
            cin >> ch;//吸收左括号
            int sum;
            cin >> sum;
            string answer;//学生答出的正确的选项
            int re = 1; //表示本题的结果,-1一半分,1满分
            int rights = 0; //学生答出的正确答案个数
            for(int b = 1; b <= sum; b++) {//输入一个选项,判断一次
                cin >> ch;
                int index = prs[a - 1].right.find(ch);
                if(index == -1) {//判断错选的
                    re = -1;//错选一个本题就0分
                    ps[a - 1].choice[ch - 'a']++;
                    if(ps[a - 1].choice[ch - 'a'] > flag)
                        flag = ps[a - 1].choice[ch - 'a'];
                } else {
                    rights++;
                    answer += ch;
                }
            }
            int thelen = prs[a - 1].right.size();
            int re2 = 1;
            for(int c = 1; c <= thelen; c++) {//判断漏选的,漏选选项,该选项也算做错
                int index = answer.find(prs[a - 1].right[c - 1]);
                if(index == -1) {
                    ps[a - 1].choice[prs[a - 1].right[c - 1] - 'a']++;
                    re2 = -1;
                    if(ps[a - 1].choice[prs[a - 1].right[c - 1] - 'a'] > flag)
                        flag = ps[a - 1].choice[prs[a - 1].right[c - 1] - 'a'];
                }
            }
            cin >> ch;//吸收右括号
            if(re == 1 && rights == thelen) {//满分
                everyscore[i - 1] += prs[a - 1].score;
            } else if(re != -1) {//一半分
                everyscore[i - 1] += prs[a - 1].score * 0.5;
            } else if(re == -1 || re2 == -1) {
                ps[a - 1].sum++;//没什么用了,可以删了
            }
        }
    }
    for(int i = 1; i <= n; i++) {
        printf("%.1lf\n", everyscore[i - 1]);
    }
    sort(ps, ps + m, cmp);//理解错题意的排序,无用了,可以删了
    int index = 0;
    if(flag == 0) {
        cout << "Too simple" << endl;
    } else {
        while(index!=m) {
            for(int i = 1; i <= 5; i++) {
                if(ps[index].choice[i - 1] == flag) {
                    cout << flag << " " << ps[index].id << "-" << (char)('a' + (i - 1)) << endl;
                }
            }
            index++;
        }
    }
    return 0;
}

理解错题意,半小时打出代码,然后测试点3/4抠了1小时,发现题意理解错了。给的测试样例也真极品(ˉ▽ˉ;)…,完美符合错误的理解方式。还是在下辣鸡啊,慢慢学吧ε=( o`ω′)ノ

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值