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 运算后判断,来统计对应的选项。

C++之异或运算符

然后还在参考代码里面看到了二维向量的初始化方式。括号里面前后两个参数分别是行和列。

vector<vector<int>> ans(0, vector<int>(3))

这个初始化方式跟 string 的括号有点相似。

二维vector的初始化

参考代码1

参考代码2

posted on 2021-09-12 16:03  Atl212  阅读(68)  评论(0)    收藏  举报

导航