GESP 202403 五级认证 T1 题解

题意理解

题面传送门
形式化题意:要排序 n n n 名同学的语数英三科考试成绩。规则:

  1. 总分高者在前;
  2. 如总分相同,比较数学和语文分数之和,高者在前;
  3. 如仍相同,比较语文和数学两科的最高分,高者靠前;
  4. 如果仍相同,则二人并列。

如果 x x x 人并列,则他们的排名相同,且要留空后面 x − 1 x-1 x1 个名次。 例如:有 3 3 3 个人并列第一,则下一个人自动成为第 4 4 4 名。且输出要按照输入顺序进行输出

思路

再输入完成后,记录下每个学生的输入顺序后,进行快速排序,然后通过操作,得出排名,最后按照输入顺序输出排名。

代码实现

对于这种排序题,我们可以使用结构体快排来实现。
首先我们来写一个自定义类型 n o d e node node,其中包含学生的三科成绩、总分、输入顺序、排名。

struct node{
	int m;//math
	int c;//Chinese
	int e;//English
	int num;//输入顺序
	int ran;//排名
	int tot;//total
};

然后输入学生人数 n n n,开一个数组 s t u stu stu,进行输入。并计算出总分和输入顺序。

cin>>n;
for(int i=0;i<n;i++){
	cin>>stu[i].c>>stu[i].m>>stu[i].e;
	stu[i].num=i;
	stu[i].tot=(stu[i].c+stu[i].e+stu[i].m);
}

然后用 C++ 内置的 s o r t sort sort 快排函数进行快排(这里不建议手写快排,因为在某些情况下,手写的快速排序可能会退为 O ( n 2 ) O(n^2) O(n2) 的时间复杂度,而 s o r t sort sort 把时间复杂度压到了 O ( n log ⁡ n ) O(n \log n) O(nlogn))。但是 s o r t sort sort 在只有两个参数的情况下,是不能对自定义数据进行排序的,所以我们可以写一个 c m p cmp cmp 比较函数来实现这个功能。
c m p cmp cmp 的基本格式如下:

bool cmp(数据类型 x, 数据类型 y){
	if(条件1){
		return 结果1;
	}else if(条件2){
		return 结果2;
	}else{//还可以写很多分支
		return 条件n;
	}
}

在这道题里,按照题面要求,应为这样:

bool cmp(node x,node y){
	if(x.tot!=y.tot){
		return x.tot>y.tot;
	}else if((x.tot-x.e)!=(y.tot-y.e)){
		return (x.tot-x.e)>(y.tot-y.e);
	}else if(max(x.c,x.m)!=max(y.c,y.m)){
		return max(x.c,x.m)>max(y.c,y.m);
	}else{
		return true;//也可以写 false
	}
}

然后我们通过这种方式:sort(stu,stu+n,cmp),进行排序。
在排序结束后,我们通过判断前后两个元素是否完全相等(按照题面的排序要求进行判断)来实现名次的计算。判断全等的代码如下:

bool all_sqe(node a,node b){
	if((a.tot==b.tot)&&((a.c+a.m)==(b.c+b.m))&&(max(a.c,a.m)==max(b.c,b.m))){
		return true;
	}else{
		return false;
	}
}

计算排名的代码如下:

	for(int i=0;i<n;i++){
		stu[i].ran=(i+1);//这里不能写 stu[i].ran=i,要不然会出现第零名
		if(all_sqe(stu[i],stu[i-1])){
			stu[i].ran=stu[i-1].ran;			
		}
	}

最后通过一个双重 f o r for for 循环来用原来的输入顺序进行输出:

	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(stu[j].num==i){
				cout<<stu[j].ran<<endl;				
			}			
		}	
	}

然后 return 0; 就收工啦。

完整代码

#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
	int m;
	int c;
	int e;
	int num;
	int ran;
	int tot;
}stu[10005];
bool cmp(node x,node y){
	if(x.tot!=y.tot){
		return x.tot>y.tot;
	}else if((x.tot-x.e)!=(y.tot-y.e)){
		return (x.tot-x.e)>(y.tot-y.e);
	}else if(max(x.c,x.m)!=max(y.c,y.m)){
		return max(x.c,x.m)>max(y.c,y.m);
	}else{
		return true;
	}
}
bool all_sqe(node a,node b){
	if((a.tot==b.tot)&&((a.c+a.m)==(b.c+b.m))&&(max(a.c,a.m)==max(b.c,b.m))){
		return true;
	}else{
		return false;
	}
}
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>stu[i].c>>stu[i].m>>stu[i].e;
		stu[i].num=i;
		stu[i].tot=(stu[i].c+stu[i].e+stu[i].m);
	}
	sort(stu,stu+n,cmp);
	for(int i=0;i<n;i++){
		stu[i].ran=(i+1);
		if(all_sqe(stu[i],stu[i-1])){
			stu[i].ran=stu[i-1].ran;			
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			if(stu[j].num==i){
				cout<<stu[j].ran<<endl;				
			}			
		}	
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值