PTA 1058 选择题

题目如下

批改多选题是比较麻烦的事情,本题就请你写个程序帮助老师批改多选题,并且指出哪道题错的人最多。

输入格式:

输入在第一行给出两个正整数 N(≤ 1000)和 M(≤ 100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……),按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。

输出格式:

按照输入的顺序给出每个学生的得分,每个分数占一行。注意判题时只有选择全部正确才能得到该题的分数。最后一行输出错得最多的题目的错误次数和编号(题目按照输入的顺序从 1 开始编号)。如果有并列,则按编号递增顺序输出。数字间用空格分隔,行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple。

输入样例:

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) (2 b d) (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) (2 b c) (4 a b c d)

输出样例

3
6
5
2 2 3 4

解题思路

这题的关键是控制输入的格式,由于在学生输入成绩的时候包含了‘(’和’)’,在输入起来比较麻烦。本人在这里提供了一种新的思路,由于C++中string并没有像python、Java语言中的split方法,因此利用find和substr构造了一个split方法。

构造split方法的代码如下:

vector<string> split(string str, string character)		// 返回一个vector容器,里面是字符串类型
{
	vector<string> vec;
	int len = character.length();		// 获取截取字符串的长度
	while (str.find(character) != -1)
	{
		int index = str.find(character);		// 计算出含有切分字符串的索引值
		vec.push_back(str.substr(0, index));		// 将切分后的子字串入vector保存
		str = str.substr(index + len);
	}
	vec.push_back(str);
	return vec;
}

构造好了split方法后可以利用构造的split方法对信息输入进行过滤。对于输入的字串其形式如下:(2 a c) (2 b d) (2 a c) (3 a b e)
则对字符串的切分可以先以") "对每道题进行切分,获得的vector中保存的字符串是(2 a c ; (2 b d ; (2 a c ; (3 a b c);注意最后一个字符串中保存了“)”,所以可以对其进行判断,当该字串为最后一题的时候用substr截取1位置的索引,长度为字符串长度-2;同样的道理,对于其他字符串也可以用substr截取然后得到每一组的字符串如下:2 a b; 2 b d; 2 a c; 3 a b c

将字符串重新整理形式之后就可以再次利用split方法对空格进行分割,取出每一组的数据了。先判断切分后的第一个数据为int型(使用atoi将字符串转化为int),然后对该值与对应题目的值进行比对,如果相等则继续往下判断每个选项的值是否与答案相同,否则直接跳过表示该题错误并且对该题错题数+1。大致的思路就是这样,代码如下:

完整代码

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
// 定义结构体,保存题目的信息(分值、选项个数、正确答案个数、正确选项)
struct question{
	int score;
	int choose_num;
	int answer_num;
	string answer;
};

vector<string> split(string str, string character)		// 返回一个vector容器,里面是字符串类型
{
	vector<string> vec;
	int len = character.length();		// 获取截取字符串的长度
	while (str.find(character) != -1)
	{
		int index = str.find(character);		// 计算出含有切分字符串的索引值
		vec.push_back(str.substr(0, index));		// 将切分后的子字串入vector保存
		str = str.substr(index + len);
	}
	vec.push_back(str);
	return vec;
}

int main()
{
	int N, M;	// 定义人数和题目数
	cin >> N >> M;
	vector<question> ques_vec;		// 用于保存题目信息的vector
	for(int i=0;i<M;i++)
	{
		question q;
		cin >> q.score >> q.choose_num >> q.answer_num;
		for(int j=0;j<q.answer_num;j++)
		{
			string s;
			cin >> s;
			q.answer+=s;
		}
		ques_vec.push_back(q);		// 每次将输入的题目信息封装成结构体保存在vector中
	}

	vector<int> corr_score(N);	// N个人的积分数组 
	vector<int> error_amount(M);	// M道题的错题数统计 

	int status = 0;		// 用于最后判断是否每一道题都正确
	string s;
	getline(cin, s);	// 一定要记住清空缓冲区!!!
	vector<string> v;
	for (int i = 0; i < N; i++)		// i个人
	{
		getline(cin, s);		// 接收每一行的学生输入题目答案
		vector<string> sp_str=split(s, ") ");		// 对字符串按照“) ”切分获得保存每道题答题信息的vector
		
		for (int j = 0; j < sp_str.size(); j++)		// 第j道题
		{
			if (sp_str[j].find(")") != -1)		// 当找到")"的时候,利用substr切分
			{
				sp_str[j] = sp_str[j].substr(1, sp_str[j].length() - 2);
			}
			else		// 字符串中没有“)”的时候进行字符串切分
			{
				sp_str[j] = sp_str[j].substr(1);
			}
			
			vector<string> ans = split(sp_str[j], " ");		//再次利用split方法对格式化后的字串进行切分,得到每题的答案
			int flag = 0;		// 初始化flag=0表示该题错误
			if (atoi(ans[0].c_str()) == ques_vec[j].answer_num)		// 当学生输入的答案个数与该题的答案数目相同时置flag=1
			{
				flag = 1;
				for (int k = 1; k < atoi(ans[0].c_str()) + 1; k++)		// 该循环用于判断每到选项是否与答案一样
				{
					if (ques_vec[j].answer.find(ans[k]) == -1)		// 如果找到一个答案不同则直接跳出循环,同时置flag=0并且将该题错误数+1
					{
						flag = 0;
						error_amount[j]++;
						break;
					}
				}
				if (flag == 1)		// 如果题目正确即返回flag=1,正确题数+1且该生分数加上该题的分数
				{
					status++;
					corr_score[i] += ques_vec[j].score;
				}
			}
			else		// 如果学生作答答案数与题目正确答案数不同,则该题错误,错误数+1
			{
				error_amount[j]++;
			}
		}
		
	}
	
	for (int i = 0; i < corr_score.size(); i++)		// 循环输出每个学生的分数
	{
		cout << corr_score[i] << endl;
	}
	if (status == N * M)		// 如果正确的题目数等于M*N即每个学生都做对了,输出Too simple
	{
		cout << "Too simple";
	}
	else
	{
		int max = 0;
		for (int i = 0; i < error_amount.size(); i++)		// 判断答错次数最多的题目的答错数量
		{
			if (error_amount[i] > max)
			{
				max = error_amount[i];
			}
		}
		cout << max;
		for (int i = 0; i < error_amount.size(); i++)		// 输出最终答错数最多的题目编号
		{
			if (error_amount[i] == max)
			{
				cout << " " << i + 1;
			}
		}
	}
	// system("pause");
}

运行结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值