[GESP202403 五级] 成绩排序 题解

洛谷 B3968 [GESP202403 五级] 成绩排序 题解

题目链接

题目大意

给定 n n n 个学生的成绩,将这 n n n 个学生的成绩按照题目要求排序后按输入顺序输出他们的排名。

题目分析

这是一道非常典型的自定义排序的题目,最关键的点就在于输出排名的时候要按照输入顺序输出,且存在日常生活中的“并列占位”情况。

对于这道题来说,我们需要一个结构体储存所有学生的信息:

struct student {
	int id, c, m, e, total, highest, sum;
	/*id为输入顺序,c,m,e含义如题所述,total记录总分,
	highest记录语文和数学的最高分,sum记录语文和数学的总分*/
} a[maxn];

下面一个问题,如何排序呢?
库函数能够支持我们自定义排序方法,可以胜任这道题目:

bool cmp(student a, student b) {//排序代码
	if (a.total > b.total) return 1;//比较总分
	else if (a.total < b.total) return 0;
	else {
		if (a.sum > b.sum) return 1;//比较语文数学分数和
		else if (a.sum < b.sum) return 0;
		else {
			if (a.highest > b.highest) return 1;//比较语文数学最高分
			else if (a.highest < b.highest) return 0;
			else return a.id < b.id;
		}
	}
}

然后就是这道题最关键的部分:如何正确地输出呢?我们不妨用一个 a n s ans ans 数组记录输出的内容。因为这时所有学生的成绩已经是从高往低排序好的,所以我们可以定义一个变量 l a s t last last 记录上一个学生的信息,如果这个学生部分信息和上一个学生部分信息相同,说明他们是并列的:

bool check(int num1, int num2) {//判断是否并列
	if (a[num1].total == a[num2].total &&
	    a[num1].sum == a[num2].sum &&
	    a[num1].highest == a[num2].highest) return 1;
	else return 0;
}

这时候我们就要考虑处理并列的问题了。我们可以定义一个 k k k,代表要额外空出几个位置。每出现一个并列的学生,就将 k k k 累加 1 1 1。需要注意的是,每次用完 k k k 之后,都要把 k k k 清零,否则会出错。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e4 + 10;
struct student {
	int id, c, m, e, total, highest, sum;
	/*id为输入顺序,c,m,e含义如题所述,total记录总分,
	highest记录语文和数学的最高分,sum记录语文和数学的总分*/
} a[maxn];
int n, p = 1;
//p记录用到了第几个位置
int k;
int ans[maxn], last;
bool cmp(student a, student b) {//排序代码
	if (a.total > b.total) return 1;//比较总分
	else if (a.total < b.total) return 0;
	else {
		if (a.sum > b.sum) return 1;//比较语文数学分数和
		else if (a.sum < b.sum) return 0;
		else {
			if (a.highest > b.highest) return 1;//比较语文数学最高分
			else if (a.highest < b.highest) return 0;
			else return a.id < b.id;
		}
	}
}
bool check(int num1, int num2) {//判断是否并列
	if (a[num1].total == a[num2].total &&
	    a[num1].sum == a[num2].sum &&
	    a[num1].highest == a[num2].highest) return 1;
	else return 0;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i].c >> a[i].m >> a[i].e;
		a[i].id = i;
		a[i].total = a[i].c + a[i].m + a[i].e;
		a[i].highest = max(a[i].c, a[i].m);
		a[i].sum = a[i].c + a[i].m;
	}
	sort(a + 1, a + n + 1, cmp);
	ans[a[1].id] = 1;
	last = 1;
	for (int i = 2; i <= n; i++) {
		if (check(last, i)) {//有并列的学生
			ans[a[i].id] = p;//记录排名
			k++;//是并列的学生,累加k
			last = i;
			continue;
		}
		p += k + 1;//并列结束,新的占位
		k = 0;//记得清空
		ans[a[i].id] = p;//记录排名
		last = i;//更新缓存信息
	}
	for (int i = 1; i <= n; i++ ) {
		cout << ans[i] << endl;
	}
	return 0;
}
  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值