1073 多选题常见计分法

在这里插入图片描述
在这里插入图片描述
思路解析:本题可以通过结构体建立实际问题模型求解,也可以利用面向过程的思想,结合二进制的知识省去很多不必要的操作。第一种方法实现起来并不难,但会显得代码冗余,在这里对第二种进行讲解。

本算法核心思想是二进制的与或运算。
1⊕1=0、1⊕0=1、0⊕1=1、0⊕0=0

下面进行分析:
分别用00001、00010、00100、01000、10000 表示A、B、C、D、E五个选项,注意在存储时是存储的对应的十进制形式,也就是1、2、4、8、16

将每道题的正确答案用二进制表示并存储起来。
如答案为ABE则对应的二进制信息是00001 + 00010 + 10000 = 10011,注意,二进制运算是在计算机内部实现的,实际操作的数仍然是十进制,比如我们对00001和00010进行与运算,实际输入的数据是“1 & 2”,计算机会自动转成二进制,而不是我们手动输入二进制数的。

批卷过程是这样的:
首先将学生该题的全部选项与正确选项进行与或运算,若结果为0则说明答案正确,否则说明有错,哪一位为1说明那个选项出错,注意:错选与空选均算出错。
比如学生答案是10001,正确答案是10101,与或结果为00100,对应的十进制是4不是0,说明有错,而其对应的选项是C,说明该学生的C项出错。

示例代码:

#include<iostream>
#include<vector>
#include<iomanip>
using namespace std;
int main(){
	int n,m; cin >> n>> m;
	int hash[] = {1,2,4,8,16};//00001 00010 00100 01000 10000 
	vector<int> trueopt(m);//m道选择题的正确答案二进制信息对应的十进制数
	int* fullscore = new int[m];//m道选择题的满分值
	for(int i = 0; i < m; i++){//读题
		int score, optnum, trunum;
		scanf("%d %d %d",&score,&optnum,&trunum);
		fullscore[i] = score;
		for(int j = 0; j < trunum; j++){//读选项
			char temp;
			scanf(" %c",&temp);
			trueopt[i] += hash[temp-'a'];//将所选答案信息全部读入到opt
		}
	}
	vector<vector<int>> cnt(m,vector<int> (5));//二维数组 存储每道题每个选项的错误次数
	for(int i = 0; i < n; i++){//执行n次 扫描每个学生
		double grade = 0;
		vector<int> stuopt(m);//创建临时数组 存储学生的答题情况
		for(int j = 0; j < m; j++){//执行m次 扫描每道题
			getchar();
			int num; //学生选中的项数
			scanf("(%d",&num);
			for(int k = 0; k < num; k++){
				char temp;
				scanf(" %c)",&temp);//捎带着吃掉末尾的)
				stuopt[j] += hash[temp-'a'];
			}
		}
		for(int k = 0; k < m; k++){//执行m次 扫描学生选中的每道题
			int el = stuopt[k] ^ trueopt[k];//进行与或运算
			if(el){//大于0 说明有错误
				if((el | trueopt[k]) == trueopt[k]){//将漏选的补上
					grade += (double)fullscore[k]/2;
				}
				if(el){//统计错误信息
					for(int j = 0; j <5; j++){//执行5次 选中5个选项
					//el存储的是有歧义的选项 所以这些选项就是所求答案
					if(el & hash[j]){
						cnt[k][j]++;
					}
				}
			}
				
			}else{
				grade += fullscore[k]*1.0;
			}
		}
		
		cout<<setprecision(1)<<fixed<<grade<<endl;
	}
		int max = 0;	//选出错的最多的那个选项
		for(int i = 0; i < m; i++){
			for(int j = 0; j < 5; j++){
				max = cnt[i][j] > max ? cnt[i][j] : max;
			}
		}
		if(!max){	//输出这些选项
			cout<<"Too simple"<<endl;
		}else{
			for(int i = 0; i < m; i++){
				for(int j = 0; j < 5; j++){
					if(cnt[i][j] == max){
						cout<<max<<" "<<i+1<<"-"<<char(j+'a')<<endl;
					}
				}
			}
		}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值