心得:
1.当题目需要输出三项关联数据的时候,考虑用二维数据,第一项是一维做一个键,第二项是二维做另一个键,第三项是结果作为值
因为一般题目要输出两项,就是最简单的键值对;当三项的时候就考虑二维数组
2.这个题和第五十八一个系列,这题更难。本来五十八题我使用的字符串匹配在这里很麻烦
第一版代码很冗杂,复用性很差。 我看了别人的思路,就觉得很好,因为选项最多5项,所以
没必要用字符串匹配,直接声明一个长度5的数组,下标代表字母,如0代表a,4代表e,出现的选项就在对应下标赋值为1,这样1代表选的,0代表没选的,由此使用对应下标做减法运算即可判断对错
题目:
批改多选题是比较麻烦的事情,有很多不同的计分方法。有一种最常见的计分方法是:如果考生选择了部分正确选项,并且没有选择任何错误选项,则得到 50% 分数;如果考生选择了任何一个错误的选项,则不能得分。本题就请你写个程序帮助老师批改多选题,并且指出哪道题的哪个选项错的人最多。
输入格式:
输入在第一行给出两个正整数 N(≤1000)和 M(≤100),分别是学生人数和多选题的个数。随后 M 行,每行顺次给出一道题的满分值(不超过 5 的正整数)、选项个数(不少于 2 且不超过 5 的正整数)、正确选项个数(不超过选项个数的正整数)、所有正确选项。注意每题的选项从小写英文字母 a 开始顺次排列。各项间以 1 个空格分隔。最后 N 行,每行给出一个学生的答题情况,其每题答案格式为 (选中的选项个数 选项1 ……)
,按题目顺序给出。注意:题目保证学生的答题情况是合法的,即不存在选中的选项数超过实际选项数的情况。
输出格式:
按照输入的顺序给出每个学生的得分,每个分数占一行,输出小数点后 1 位。最后输出错得最多的题目选项的信息,格式为:错误次数 题目编号(题目按照输入的顺序从1开始编号)-选项号
。如果有并列,则每行一个选项,按题目编号递增顺序输出;再并列则按选项号递增顺序输出。行首尾不得有多余空格。如果所有题目都没有人错,则在最后一行输出 Too simple
。
思路:
这个题个人觉得说明不明确,题目说要求记录错误的选项,这个"错误的选项"意思不止是选错的选项(即多选了一个错误的选项),还有漏选的选项(即少选了一个正确的选项),需要注意
第一版我使用了字符串匹配,很麻烦,基本很难看懂
在看了别人思想更进了代码之后,就很明确了
就是声明一个长度5的选项数组,下标代表字母,如0代表a,4代表e,出现的选项就在对应下标赋值为1,这样1代表选的,0代表没选的,然后将正确答案和学生选的答案进行比较(这里我直接做减法来判断),就可以判断是否做错或者做全对或者做部分对
第一版代码:
#include<iostream>
#include<map>
#include<vector>
#include<cstdio>
using namespace std;
struct ques
{
int score;
int opt_num;
int right_num;
string ans;
};
int main()
{
int stu_num,ques_num,max_num=0;
vector<ques> q;
cin>>stu_num>>ques_num;
int right_opt[ques_num][5]={};
int wrong_opt_num[ques_num][5]={};
for(int i=0;i<ques_num;i++)
{
ques temp;
string t_str="";
char t_ch;
cin>>temp.score>>temp.opt_num>>temp.right_num;
for(int j=0;j<temp.right_num;j++)
{
cin>>t_ch;
right_opt[i][t_ch-'a']=1;
t_str+=t_ch;
}
temp.ans=t_str;
q.push_back(temp);
}
for(int i=0;i<stu_num;i++)
{
double this_stu_score=0.0;
for(int j=0;j<ques_num;j++)
{
cin.ignore();
bool is_wrong=false;
int this_opt_num;
string this_ans="";
char t_ch,t_c;
scanf("(%d",&this_opt_num);
for(int k=0;k<this_opt_num;k++)
{
cin>>t_ch;
this_ans+=t_ch;
}
scanf(")");
if(this_ans.size()==q.at(j).ans.size())
{
for(int k=0;k<q.at(j).ans.size();k++)
{
int t=this_ans.find(q.at(j).ans.at(k));
if(t==this_ans.npos)
wrong_opt_num[j][q.at(j).ans.at(k)-'a']++;
if(wrong_opt_num[j][q.at(j).ans.at(k)-'a']>max_num)
max_num=wrong_opt_num[j][q.at(j).ans.at(k)-'a'];
}
for(int k=0;k<q.at(j).ans.size();k++)
{
if(right_opt[j][this_ans.at(k)-'a']!=1)
{
is_wrong=true;
wrong_opt_num[j][this_ans.at(k)-'a']++;
if(wrong_opt_num[j][this_ans.at(k)-'a']>max_num)
max_num=wrong_opt_num[j][this_ans.at(k)-'a'];
}
}
if(!is_wrong)
this_stu_score+=q.at(j).score;
}
else
{
for(int k=0;k<q.at(j).ans.size();k++)
{
int t=this_ans.find(q.at(j).ans.at(k));
if(t==this_ans.npos)
wrong_opt_num[j][q.at(j).ans.at(k)-'a']++;
if(wrong_opt_num[j][q.at(j).ans.at(k)-'a']>max_num)
max_num=wrong_opt_num[j][q.at(j).ans.at(k)-'a'];
}
for(int k=0;k<this_ans.size();k++)
{
if(right_opt[j][this_ans.at(k)-'a']!=1)
{
is_wrong=true;
wrong_opt_num[j][this_ans.at(k)-'a']++;
if(wrong_opt_num[j][this_ans.at(k)-'a']>max_num)
max_num=wrong_opt_num[j][this_ans.at(k)-'a'];
}
}
if(!is_wrong)
this_stu_score+=q.at(j).score*1.0/2;
}
}
printf("%.1f\n",this_stu_score);
}
if(max_num==0)
printf("Too simple\n");
else
{
for(int i=0;i<ques_num;i++)
{
for(int j=0;j<5;j++)
{
if(wrong_opt_num[i][j]==max_num)
printf("%d %d-%c\n",max_num,i+1,j+'a');
}
}
}
return 0;
}
第二版代码:
#include<iostream>
#include<map>
#include<vector>
#include<cstdio>
using namespace std;
struct ques
{
int score;
int opt_num;
int right_num;
int right_opt[5]={};//这个数组是每个题的正确答案
};
int main()
{
int stu_num,ques_num,max_num=0;
cin>>stu_num>>ques_num;
int wrong_opt_num[ques_num][5]={};//这个二维数组就是记录某个题的某个选项的错误次数
vector<ques> q;
for(int i=0;i<ques_num;i++)
{
ques temp;
char t_ch;
cin>>temp.score>>temp.opt_num>>temp.right_num;
for(int j=0;j<temp.right_num;j++)
{
cin>>t_ch;
temp.right_opt[t_ch-'a']=1;//对应的下标赋值为1
}
q.push_back(temp);
}
for(int i=0;i<stu_num;i++)
{
double this_stu_score=0.0;
for(int j=0;j<ques_num;j++)
{
int stu_opt_num;
char t_ch;
bool is_wrong=false,is_part=false;
int opt[5]={};//这个数组存学生选择的选项
cin.ignore();
scanf("(%d",&stu_opt_num);
for(int k=0;k<stu_opt_num;k++)
{
cin>>t_ch;
opt[t_ch-'a']=1;//也是对应下标赋值为1
}
cin.ignore();
for(int k=0;k<5;k++)
{//这个循环开始对每个选项判断
int num=opt[k]-q.at(j).right_opt[k];//学生的选择和答案做减法
if(num==1||num==-1)
{//如果num=1说明多选了,即选了一个错误选项
//如果num=-1说明少选了,即没选某个正确选项
//这两种情况都是题目所说的"错误的选项"
wrong_opt_num[j][k]++;
if(wrong_opt_num[j][k]>max_num)
max_num=wrong_opt_num[j][k];
if(num==1)
is_wrong=true;
if(num==-1)
is_part=true;
}
}
if(!is_wrong&&!is_part)//如果没多选也没少选,就给满分
this_stu_score+=q.at(j).score;
else if(!is_wrong&&is_part)//如果没多选但少选了,就给一般分
this_stu_score+=q.at(j).score*1.0/2;
}
printf("%.1f\n",this_stu_score);
}
if(max_num==0)
printf("Too simple\n");
else
{
for(int i=0;i<ques_num;i++)
{
for(int j=0;j<5;j++)
{
if(wrong_opt_num[i][j]==max_num)
printf("%d %d-%c\n",max_num,i+1,j+'a');
}
}
}
return 0;
}