批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数;如果考生选择了任何一个错误的选项,则不能得分。本题就请你写个程序帮助老师批改多选题,并且指出哪道题的哪个选项错的人最多。
输入在第一行给出两个正整数 N(≤1000)和 M(≤100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……)
,按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。
按照输入的顺序给出每个学生的得分,每个分数占一行,输出小数点后 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) (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)
3.5
6.0
2.5
2 2-e
2 3-a
2 3-b
2 2
3 4 2 a c
2 5 1 b
(2 a c) (1 b)
(2 a c) (1 b)
5.0
5.0
Too simple
本题 1073 和 1058 多选题 输入格式相同 ,但是比较内容和输出结果不同 核心部分和 1058基本相同, 在于截取不等长的括号中 字符串
在这道题目中使用了集合 set<int> 和 面向对象的编程方式,初始化并统计了题目和答题信息
因为本题给出的数据具有一定的顺序, 比如说 学生答题字符串中一定是 选项个数 n 在左括号后第一位, 之后紧跟着n个选项和 1 个右括号 , 可以通过循环遍历字符串来获取选项信息,并不需要使用集合方式来获取
对于快速ac本题这一目的来说, 使用集合和面向对象编程并没有太大帮助, 由于我刚开始学习使用c++所以本题目使用了这种方法
集合的方法 (需要 algorithm头文件)
并集 set_union(A.begin(),A.end(),B.begin(),B.end(),inserter(c,c.begin()));
//参数分别为 A集合开始结束迭代器,B集合开始结束迭代器,插入器(集合名,插入位置), 插入器元素来自A B集合
交集 set_intersection(A.begin(),A.end(),B.begin(),B.end(),inserter(c,c.begin()));
//参数分别为 A集合开始结束迭代器,B集合开始结束迭代器,插入器(集合名,插入位置), 插入器元素来自A B的交集
差集 set_difference(A.begin(),A.end(),B.begin(),B.end(),inserter(c,c.begin()));
//参数分别为 A集合开始结束迭代器,B集合开始结束迭代器,插入器(集合名,插入位置), 插入器元素来自A集合
差集相当于 A集合 减去 AB交集 并不是A B中不相交的部分
解题思路
1.除录入题目信息外, 学生答题信息和1058的处理类似, 也是统计答题信息 然后和题目的正确答案比较
2.要注意 答错的选项 ,并不是只有选错的错误选项, 还包含了漏选的正确选项
因此要统计的 答错的选项 中有两种选项, 一种是漏选的正确选项 另一种是多选的错误选项
如果是有答错的选项,用选项集合减去正确选项集合就是 多选的错误选项
如果有漏选的选项,用正确选项集合减去选项集合就是 漏选的正确选项
3. 当一道题目的答题情况不是满分时,要统计错误信息(漏选和多选), 同时更新该道题目中 错误选项的次数
4.最终输出的时候 找出每道题目中选项错误次数最多的次数 然后将每道题中的选项错误次数 与 最多错误次数 相同的选项输出
#include <iostream> #include <vector> #include <algorithm> #include <string> #include <iomanip> #include <set> using namespace std; class question{ public: int index;//题目序号 double maxPt;//题目满分 set<int> cA;//correctAnswer 正确选项 vector<int> falseOptions;//序号代表选项 0 = ‘a‘ 4 = ‘e‘ 值为错误次数 int maxFalseTime{-1};//本题选项错误最大值 初值为-1 question()=default; question(int i,set<int> ca,int opsNums,double mpt):index{i},cA{ca},falseOptions(opsNums,0),maxPt{mpt}{} void printFalseOptions(int max){//输出 和最多次错误次数相同的 错误选项信息 for(int i=0;i<falseOptions.size();i++){//检验每个选项的错误次数 if(falseOptions[i]==max){//是否 和 题目选项最多错误次数 相等,是则输出信息 cout <<falseOptions[i]<<" "<<index+1<<"-"<<static_cast<char>(i+static_cast<int>(‘a‘))<<endl; } } }; void updateFalseTime(int optIndex){//更新选项错误次数 falseOptions[optIndex]++; maxFalseTime=falseOptions[optIndex]>maxFalseTime?falseOptions[optIndex]:maxFalseTime; } double getPoint(set<int> an){//对提交的答案进行判断 an为学生答案 double scour{0}; int condition{0};//0为题目答错 1为全对 2为 不全对 set<int> is;//交集结果intersectionSet set<int> us;//并集结果unionSet set<int> ds;//差集结果differenceSet //答题选项与正确答案的交集 结果插入is中 set_intersection(cA.begin(),cA.end(),an.begin(),an.end(),inserter(is, is.begin())); //答题选项与正确答案的并集 结果插入us中 set_union(cA.begin(),cA.end(),an.begin(),an.end(),inserter(us, us.begin())); //答题选项与正确答案的差集 结果插入到ds中 //少选 既漏选的选项, 用正确答案减去交集就是漏选选项 //参数分别为 A集合开始结束迭代器,B集合开始结束迭代器,插入器(集合名,插入位置), 插入器元素来自A集合 set_difference(cA.begin(),cA.end(),is.begin(),is.end(),inserter(ds, ds.begin())); //多选//既错选时的选项集合 用并集减去正确答案就是错选集合 参数与上相同 set_difference(us.begin(),us.end(),cA.begin(),cA.end(),inserter(ds, ds.begin())); if(is==cA&&us==cA){//如果答案与正确答案的交集相同 且并集相同 说明学生选择了正确答案 得分满分 condition=1; }else if(is!=cA&&us==cA){//交集与正确答案不同 但是并集和正确答案相同 说明有正确选项但是不全 condition=2; }else{//其他情况均为错误 condition=0; } switch (condition) { case 0:scour=0;break;//如果有错误选项 case 1:scour=maxPt;break;//全对 case 2:scour=maxPt/2;;break;//有漏选 default:break; } if(condition!=1){//有漏选或者错选时,统计错误选项 set<int>::iterator itcur=ds.begin(); set<int>::iterator itend=ds.end(); for(;itcur!=itend;itcur++){//遍历错误选项集合的元素, updateFalseTime(*itcur);//更新错误选项计数 } } return scour; } }; set<int> getOpt(string str){ set<int> sets; for(int i=0;i<str.size();i++){ if(str[i]>=‘a‘&&str[i]<=‘e‘){ sets.insert(static_cast<int>(str[i]-‘a‘)); } } return sets; } int main(){ int n,m,corOptNums,OptNums; double maxpt; set<int> opts;//题目选中的选项 int 0-4分别代表a-e vector<question> qs;//问题集 string str; cin >> n >> m;//学生人数 选择题数量 //录入题目 for(int i=0;i<m;i++){ cin >> maxpt >> OptNums >> corOptNums; getline(cin,str); question q(i,getOpt(str),OptNums,maxpt); qs.push_back(q); } for(int i=0;i<n;i++){//每个学生判断一次 getline(cin,str); //拆分字符串 int left{0},right{0},count{0}; double scour{0}; string temp; int j=0; while(left<str.size()&&j<m){ if(str[left]==‘(‘){ right=left; while(right<str.size()){ if(str[right]==‘)‘){ temp=str.substr(left+1,count-1); scour+=qs[j++].getPoint(getOpt(temp)); count=0; break; } right++; count++; } } left++; } cout.setf(ios::fixed); cout<<setprecision(1)<< scour<<endl; } int max{-1}; for(int i=0;i<m;i++){//找出最大选项错误次数 if(qs[i].maxFalseTime>max){ max=qs[i].maxFalseTime; } } if(max<=0){//没有错题 cout << "Too simple"<<endl; }else{ for(int i=0;i<m;i++){ qs[i].printFalseOptions(max); } } return 0; }
PTA basic 1073 多选题常见计分法 (20 分) c++语言实现(g++)
原文:https://www.cnblogs.com/ichiha/p/14756614.html