信息学奥赛一本通 1179:奖学金 | 1938:【07NOIP普及组】奖学金 | OpenJudge NOI 1.10 04 | 洛谷 P1093 [NOIP2007 普及组] 奖学金

【题目链接】

ybt 1179:奖学金
ybt 1938:【07NOIP普及组】奖学金
OpenJudge NOI 1.10 04:奖学金
洛谷 P1093 [NOIP2007 普及组] 奖学金

【题目考点】

1. 排序

【君义精讲】排序算法

2. 多关键字排序

方法1:将多关键字的排序条件整合为单一排序条件
方法2:使用稳定的排序算法进行多趟排序

【解题思路】

设结构体表示学生信息,保存人名、学号及各科成绩

解法1:将多关键字的排序条件整合为单一排序条件

可以将该排序条件设为函数:函数传入两个学生的结构体对象a与b
如果a与b的总成绩及语文成绩相同,学号小的排在前面。
如果a与b的总成绩相同但语文成绩不同,语文成绩高的排在前面。
如果a与b的总成绩不同,总成绩高的排在前面。
当然,也可以将整个条件写为一个表达式。
排序方法可以任意选择。

解法2:使用稳定的排序算法进行多趟排序

先按学号从小到大排序
再按语文成绩从高到低排序
再按总成绩从高到低排序。
只能选择稳定的排序方法。

【题解代码】

解法1:将多关键字的排序条件整合为单一排序条件
  • 函数写法1 + 插入排序
#include<bits/stdc++.h>
using namespace std;
struct Stu
{
	int id, Chinese, score;//id:编号 Chinese:语文成绩 score:总成绩 
};
bool isPrior(Stu d1, Stu d2)//比较函数 判断d1是否应该在d2前面
{
	if(d1.score > d2.score)//比较总分 
		return true;
	else if(d1.score < d2.score)
		return false;
	else//总分数相等 
	{
		if(d1.Chinese > d2.Chinese)//比较语文成绩 
			return true;
		else if(d1.Chinese < d2.Chinese)
			return false;
		else//语文成绩相等 
		{
			if(d1.id < d2.id)//比较学号 
				return true;
			else
				return false;
		}	
	}	
}
int main()
{
   	int n, a, b, c;//n:人数 a,b,c:语文,数学,英语成绩
   	cin >> n;
	Stu d[305]; 
   	for(int i = 1; i <= n; ++i)
   	{
   		cin >> a >> b >> c;
   		d[i].id = i;
   		d[i].Chinese = a;
   		d[i].score = a+b+c;
	}
	for(int i = 2; i <= n; ++i)//插入排序 
	{
		for(int j = i; j > 1; --j)
		{
			if(isPrior(d[j], d[j-1]))
                swap(d[j], d[j-1]);
			else
				break;
		}
	}
	for(int i = 1; i <= 5; ++i)
		cout << d[i].id << ' ' << d[i].score << endl;
    return 0;
}
  • 函数写法2 + STL sort函数排序
#include<bits/stdc++.h>
using namespace std;
struct Stu
{
	int id, Chinese, score;//id:编号 Chinese:语文成绩 score:总成绩 
};
bool cmp(Stu d1, Stu d2)//比较函数 判断d1是否应该在d2前面
{
    if(d1.score == d2.score && d1.Chinese == d2.Chinese)
        return d1.id < d2.id;
    else if(d1.score == d2.score)
        return d1.Chinese > d2.Chinese;
    else
        return d1.score > d2.score;
}
int main()
{
   	int n, a, b, c;//n:人数 a,b,c:语文,数学,英语成绩
   	cin >> n;
	Stu d[305]; 
   	for(int i = 1; i <= n; ++i)
   	{
   		cin >> a >> b >> c;
   		d[i].id = i;
   		d[i].Chinese = a;
   		d[i].score = a+b+c;
	}
	sort(d+1, d+1+n, cmp); 
	for(int i = 1; i <= 5; ++i)
		cout << d[i].id << ' ' << d[i].score << endl;
    return 0;
}
  • 写成表达式 + 冒泡排序
#include<bits/stdc++.h>
using namespace std;
struct Stu
{
	int id, Chinese, score;//id:编号 Chinese:语文成绩 score:总成绩 
};
bool isPrior(Stu d1, Stu d2)//比较函数 判断d1是否应该在d2前面
{
    return d1.score > d2.score || 
        d1.score == d2.score && d1.Chinese > d2.Chinese ||
        d1.score == d2.score && d1.Chinese == d2.Chinese && d1.id < d2.id;
}
int main()
{
   	int n, a, b, c;//n:人数 a,b,c:语文,数学,英语成绩
   	cin >> n;
	Stu d[305]; 
   	for(int i = 1; i <= n; ++i)
   	{
   		cin >> a >> b >> c;
   		d[i].id = i;
   		d[i].Chinese = a;
   		d[i].score = a+b+c;
	}
	for(int i = 1; i <= n-1; ++i)//冒泡排序 
	   for(int j = 1; j <= n-i; ++j)
	       if(isPrior(d[j+1], d[j]))//如果d[j+1]应该在d[j]前面 
	           swap(d[j], d[j+1]);
	for(int i = 1; i <= 5; ++i)
		cout << d[i].id << ' ' << d[i].score << endl;
    return 0;
}
解法2:使用稳定的排序算法进行多趟排序
#include<bits/stdc++.h>
using namespace std;
struct Stu
{
	int id, Chinese, score;//id:编号 Chinese:语文成绩 score:总成绩 
};
bool cmp1(Stu d1, Stu d2)
{
    return d1.id < d2.id;
}
bool cmp2(Stu d1, Stu d2)
{
    return d1.Chinese > d2.Chinese;
}
bool cmp3(Stu d1, Stu d2)
{
    return d1.score > d2.score;
}
int main()
{
   	int n, a, b, c;//n:人数 a,b,c:语文,数学,英语成绩
   	cin >> n;
	Stu d[305]; 
   	for(int i = 1; i <= n; ++i)
   	{
   		cin >> a >> b >> c;
   		d[i].id = i;
   		d[i].Chinese = a;
   		d[i].score = a+b+c;
	}
    stable_sort(d+1, d+1+n, cmp1);//学号从小到大
    stable_sort(d+1, d+1+n, cmp2);//语文从大到小
    stable_sort(d+1, d+1+n, cmp3);//总分从大到小 
	for(int i = 1; i <= 5; ++i)
		cout << d[i].id << ' ' << d[i].score << endl;
    return 0;
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值