信息学奥赛一本通 1180 | 1946:【09NOIP普及组】分数线划定 | OpenJudge NOI 1.10 05 | 洛谷 P1068 [NOIP2009 普及组] 分数线划定

【题目链接】

ybt 1180:分数线划定
ybt 1946:【09NOIP普及组】分数线划定
OpenJudge NOI 1.10 05:分数线划定
洛谷 P1068 [NOIP2009 普及组] 分数线划定

【题目考点】

1. 排序

【君义精讲】排序算法

【解题思路】

该题要排序的元素个数最大为5000,选用 O ( n 2 ) O(n^2) O(n2)的排序算法即可。
基本思路为:先按照“先按成绩降序排序,成绩相同按报名号升序排序”这样的排序规则对输入的数据进行排序,取第 ⌊ m ∗ 1.5 ⌋ \lfloor m*1.5 \rfloor m1.5个人的分数线,再看分数大于等于分数线的人数有多少,再把这些人的信息输出。
可选的写法有:

  1. 设结构体而后定义结构体变量的排序规则。
  2. 直接写出排序规则
  3. 用稳定的排序算法,先按报名号排序,再按成绩排序

【题解代码】

解法1:设结构体,使用sort函数排序
#include <bits/stdc++.h>
using namespace std;
#define N 5005
struct Stu
{
	int k, s;//k:报名号 s:成绩	
};
bool cmp(Stu &a, Stu &b)
{
	if(a.s == b.s)//如果分数相同 
		return a.k < b.k;//报名号小的在前面 
	else//如果分数不同 
		return a.s > b.s;//成绩高的在前面 
}
int main()
{
	Stu stu[N];
	int n, m, line, ct = 0;//line:分数线 ct:人数 
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> stu[i].k >> stu[i].s;
	sort(stu+1, stu+1+n, cmp);//根据cmp指定的规则进行排序 
	line = stu[int(m*1.5)].s;//确定分数线
	for(int i = 1; i <= n; ++i)
	{
		if(stu[i].s >= line)
			ct++;
	}
	cout << line << ' ' << ct << endl;
	for(int i = 1; i <= ct; ++i)//输出前ct个人的信息 
		cout << stu[i].k << ' ' << stu[i].s << endl;
	return 0;
}
解法2:不用结构体 冒泡排序 直接写出排序规则
#include <bits/stdc++.h>
using namespace std;
#define N 5005
int main()
{ 
	int k[N], s[N], n, m, line, ct = 0;//line:分数线 ct:人数 
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> k[i] >> s[i];
	for(int i = 1; i <= n - 1; ++i)
		for(int j = 1; j <= n - i; ++j)
		{
			if(s[j] < s[j+1] || s[j] == s[j+1] && k[j] > k[j+1])//如果右面的分数高,或分数相同时右面的编号小,要交换
			{
				swap(s[j], s[j+1]);
				swap(k[j], k[j+1]);
			} 
		}
	line = s[int(m*1.5)];//确定分数线
	for(int i = 1; i <= n; ++i)
	{
		if(s[i] >= line)
			ct++;
	}
	cout << line << ' ' << ct << endl;
	for(int i = 1; i <= ct; ++i)//输出前ct个人的信息 
		cout << k[i] << ' ' << s[i] << endl;
	return 0;
}
解法3:计数排序+插入排序 使用二维数组记录要输出的数字,而后输出
#include <bits/stdc++.h>
using namespace std;
int score[105][5005] = {};//score[i]:分数为i的各个人的编号 score[i][0]为score[i]这个一维数组的长度 
int main()
{ 
	int k, s, n, m, line, ct = 0;//line:分数线 ct:人数 
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
	{
		cin >> k >> s;
		score[s][++score[s][0]] = k;//把k插入score[s]数组,做插入排序,依编号从小到大排序
		for(int j = score[s][0]; j > 1; --j)
		{ 
			if(score[s][j] < score[s][j-1])
				swap(score[s][j], score[s][j-1]);
			else
				break;
		}
	}
	int lnum = int(m*1.5);//lnum:第几个人的分数为分数线 
	for(int i = 100; i >= 0; --i)
	{
		ct += score[i][0];//分数为i的人有score[i][0]个人
		if(ct >= lnum)
		{
			line = i;
			break; 
		}
	}
	cout << line << ' ' << ct << endl;
	for(int i = 100; i >= line; --i)//输出分数到line的人的信息
		for(int j = 1; j <= score[i][0]; ++j)
			cout << score[i][j] << ' ' << i << endl;
	return 0;
}
解法4:用stable_sort稳定的排序进行两趟排序

选用任意一种稳定的排序都可以

#include <bits/stdc++.h>
using namespace std;
#define N 5005
struct Stu
{
	int k, s;//k:报名号 s:成绩	
};
bool cmp_k(const Stu &a, const Stu &b)//编号比较规则 
{
	return a.k < b.k; 
}
bool cmp_s(const Stu &a, const Stu &b)//分数比较规则 
{
	return a.s > b.s; 
}
int main()
{
	Stu stu[N];
	int n, m, line, ct = 0;//line:分数线 ct:人数 
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> stu[i].k >> stu[i].s;
	stable_sort(stu+1, stu+1+n, cmp_k);//先根据编号比较,再根据分数比较
	stable_sort(stu+1, stu+1+n, cmp_s);//先根据编号比较,再根据分数比较
	line = stu[int(m*1.5)].s;//确定分数线
	for(int i = 1; i <= n; ++i)
	{
		if(stu[i].s >= line)
			ct++;
	}
	cout << line << ' ' << ct << endl;
	for(int i = 1; i <= ct; ++i)//输出前ct个人的信息 
		cout << stu[i].k << ' ' << stu[i].s << endl;
	return 0;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值