PAT 乙级练习 1073 多选题常见计分法 - 超级详细的思路讲解

PAT 乙级练习 题解合集

本题链接

题目

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

思路

1. 处理M道题的输入

problems记录M个题目信息(见下方代码),其中point表示该题分值,ans的设定有一点复杂,允许我举例说明:

例如,对于输入3 4 2 a cpoint的值是3ans"aBcD",字符串长度为 4 表示总共有 4 个选项,其中小写的两个字母代表正确选项。

又例如,输入1 5 4 a b d eans应该是abCde

struct Problem {
	double point;
	string ans;
};
vector<Problem> problems(m);

2. 输入答卷的同时给出成绩,对错误选项计数

  1. vector > wrongCnt(m, vector(5, 0));
    定义wrongCnt对错误选项计数;
  2. 对于第i名学生,用sum来统计其总分,每一轮开始时要初始化为 0;
  3. 对于第i名学生答的第j道题,按照以上提及的答案表示方法生成对应的字符串ans,例如一个题总共有 5 个选项,学生选了ab,那么生成abCDE
  4. 如果ans == problems[j].ans,那么完全正确,为sum增加该题的分值;
  5. 如果ans != problems[j].ans,需要用k遍历两个字符串来比较其区别
    a. 只要遇到ans[k] != problems[j].ans[k],说明这个选项错了,wrongCnt中对应的选项要计数 1 次;
    b. 还要判断是什么样的错误,如果是多选的情况,那么该生这一题全错;
    遍历结束后,如果该生没有多选,说明是漏选,要为sum加上这个题一半的分值。
  6. 批完第i名学生的考卷后立即输出其sum

3. 找到最大的错误次数,输出这些选项

  1. 遍历wrongCnt,找到最大的错误次数maxWrongCnt
  2. 如果maxWrongCnt == 0,输出Too simple
  3. 否则,再次遍历wrongCnt,输出所有错得最多的选项。

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;
const string ABCDE = "ABCDE";
struct Problem {
	double point;
	string ans;
};
int main() {
	int n, m, len, correctCnt;
	string input;
	cin >> n >> m;
	vector<Problem> problems(m);
	vector<vector<int> > wrongCnt(m, vector<int>(5, 0));
	for (int i = 0; i < m; ++i) {
		cin >> problems[i].point >> len >> correctCnt;
		problems[i].ans = ABCDE.substr(0, len);
		while (correctCnt--) {
			cin >> input;	// 小写代表正确选项
			int temp = ABCDE.find(toupper(input[0]));
			problems[i].ans[temp] = tolower(problems[i].ans[temp]);
			wrongCnt[i][temp] = 0;
		}
	}
	getline(cin, input);	// 吃回车 
	for (int i = 0; i < n; ++i) {	// 每个学生 
		double sum = 0.0;
		getline(cin, input);
		int p = 0;
		for (int j = 0; j < m; ++j) {	// 每道题
			bool wrong = false;
			while (input[p] != '(')
				++p;
			int cnt = input[++p] - '0';
			string ans = ABCDE.substr(0, problems[j].ans.size());
			for (int k = 0; k < cnt; ++k) {		// 读入答题卡选项 
				p += 2;
				int temp = ABCDE.find(toupper(input[p]));
				ans[temp] = tolower(ans[temp]);
			}
			if (ans == problems[j].ans)
				sum += problems[j].point;
			else {
				for (int k = 0; k < ans.size(); ++k) {	// 对比每个选项 
					if (ans[k] != problems[j].ans[k]) {
						++wrongCnt[j][k];
						if (ans[k] > problems[j].ans[k])
							wrong = true;
					}
				}
				if (!wrong)
					sum += 0.5 * problems[j].point;
			} 
		}
		printf("%.1lf\n", sum); 
	}
	int maxWrongCnt = 0;
	for (int i = 0; i < m; ++i)
		for (int j = 0; j < 5; ++j)
			if (wrongCnt[i][j] > maxWrongCnt)
				maxWrongCnt = wrongCnt[i][j];
	if (maxWrongCnt == 0)
		puts("Too simple");
	else
		for (int i = 0; i < m; ++i)
			for (int j = 0; j < 5; ++j)
				if (wrongCnt[i][j] == maxWrongCnt)
					printf("%d %d-%c\n", maxWrongCnt, i + 1, tolower(ABCDE[j]));
	return 0;
} 

你可能感兴趣的:(PAT,乙级)