1073 多选题常见计分法 (20 point(s))
#include <bits/stdc++.h>
using namespace std;
struct Question{
double score, num, cor;
set<char> copt;
map<char, int> fault;
};
int main() {
// 输入 学生人数 多选题个数
int n, m;
vector<Question> qt;
cin >> n >> m;
// 满分值 选项个数 正确选项个数 正确选项
for(int i = 0; i < m; i++){
double score, num, cor;
Question tmp;
cin >> score >> num >> cor;
tmp = {score, num, cor};
// 输入正确选项
while(cor--){
char c;
cin >> c;
tmp.copt.insert(c);
}
// 输入完数据存入向量
qt.push_back(tmp);
}
// 输入学生信息
while(n--){
// 遍历每个题目
double sum = 0;
for(auto& q : qt){
double num, cnum = 0, right = true;
set<char> stu;
char c;
// 读取左 '(" 和学生选项数
cin >> c >> num;
// 读取学生选项
while(num--){
cin >> c;
stu.insert(c);
}
// 遍历学生选项
for(auto s: stu){
// 选择错误
if(q.copt.count(s) == 0){
right = false;
q.fault[s]++;
}
// 累计正确选项数
else cnum++;
}
// 遍历正确选项 找没选出选项
for(auto opt: q.copt)
if(stu.find(opt) == stu.end()){
q.fault[opt]++;
}
// 错一个不得分
if(right == false) sum += 0;
// 全对
else if(cnum == q.cor) sum += q.score;
// 部分
else sum += q.score / 2;
// 读取右 ')"
cin >> c;
}
// 输出得分
cout << fixed << setprecision(1) << sum << endl;
}
// 遍历所有题目所有选项找到最大错误的人数
int maxPeo = 0;
for(auto q: qt)
for(auto f: q.fault)
if(maxPeo < f.second)
maxPeo = f.second;
// 没有错误
if(maxPeo == 0) cout << "Too simple";
else{
// 遍历每一道题目的选项 找到错误人数最多的
int i = 1;
for(auto q: qt){
for(auto f: q.fault)
if(maxPeo == f.second)
cout << maxPeo << " " << i << "-" << f.first << endl;
// 指向下一题目
i++;
}
}
}
这题当时改了半天的bug,最后发现不小心把正确选项的 map 容器,同时当成了用来记录错误选项的容器,这就导致找选项时错误选项也算在了里面。这是没有明确变量,记录的容器导致的问题。
for (int k = 0; k < temp; k++) {
scanf(" %c)", &c);
opt[i][j] += hash[c-'a'];
}
int el = opt[i][j] ^ trueopt[j];
if (el) {
if ((opt[i][j] | trueopt[j]) == trueopt[j]) {
grade += fullscore[j] * 1.0 / 2;
}
if (el) {
for (int k = 0; k < 5; k++)
if (el & hash[k]) cnt[j][k]++;
}
} else {
grade += fullscore[j];
}
学了学别人用位运算来判断学生答案和正确答案是否一致。首先用二进制来存储答案,00001 00010 00100 01000 10000 可以分别对应 a b c d e 。首先将二进制转换成十进制有 1 2 4 8 16 然后存在一个散列数组里面,在输入 a b 的时候减去 a 字符,得到下标来对应数字。输入学生答案也有类似的操作。
然后是位运算。这里参与的分别有异或、或和与运算。异或的运算时 0 ^ 0 = 0, 0 ^ 1 = 1 1 ^ 1 = 0。或和与就不说了。
实际处理时用具体的例子说明比较直观,假设正确答案是 a c 学生答案是 a b c 有二进制 00101 00111,经过异或,或和与运算。
异或 或 与
00101 00010 00010
^00111 |00101 &00010
----- ----- -----
00010 00111 00010
可以看到,异或将选错的选项 b 给拎了出来,正确的都变成了 0 。而在后面的或和与的运算中,或运算会将部分 0 的补成 1 ,补全 1 后如果跟正确选项一致就是部分正确但是漏选。但显然这里 b 是错选,所以判断不为部分正确。
与运算会找出每个错误的选项。将 a 到 e 都循环一次,通过与运算比对两个二进制的位是否一致,部分选对和错选的都会通过 1 & 1 = 1 运算后判断,来统计对应的选项。
然后还在参考代码里面看到了二维向量的初始化方式。括号里面前后两个参数分别是行和列。
vector<vector<int>> ans(0, vector<int>(3))
这个初始化方式跟 string 的括号有点相似。
浙公网安备 33010602011771号