排序——如何动态修改中维护顺序

文章没更完,未完待续……

题目描述

又到了一年一度的大学的保研推免时间了,某大学推出了保研的规则:

绩点保研名额:人数在 5 5 5 人以下时,绩点第 1 1 1 的同学可以获得名额;人数大于等于 5 5 5 人时,每个班级绩点在前 20 % 20\% 20%(人数向下取整)的同学可以获得绩点保研名额,如果有多个同学绩点并列第 20 % 20\% 20% 名,则学号小的同学优先获得名额,不能超过 20 % 20\% 20%

竞赛保研名额:参加了国家级比赛并获得一等奖的同学可以获得竞赛保研名额。

获得竞赛保研名额的同学如果处于绩点保研的范围内,则他的绩点保研名额可以顺延到绩点排名在他后面的同学。

为了及时获取保研同学的最低绩点,你需要在每个同学的信息输入后,马上求出获得绩点保研同学的最后一名同学的学号和绩点。

分析

很容易想到每次都排序一遍,而遇到竞赛的就忽略他不把他加入排序数组内。

但是这样子的时间复杂度为 O ( n 2 log ⁡ 2 n ) O(n^2\log_2 n) O(n2log2n),不能通过。

所以可以每次从后往前做一遍冒泡,维护数组的顺序,这样就可以避免每次都排序的时间浪费了,时间复杂度为 O ( n 2 ) O(n^2) O(n2),貌似可以用 链表+二分 优化到 O ( n ) O(n) O(n)

代码

#include 

using namespace std;

const int N = 20005;
int n;
struct node{
	int id;
	double score;
}a[N]; 

int main(){
	cin >> n;	
	int x, now = 0;
	double y;
	char c;
	cout << fixed << setprecision(2);
	for(int i = 1; i <= n; i ++){
		cin >> x >> y >> c;
		if(c == 'Y'){
			int o = max(i / 5, 1);//计算保研的人数,不足5人就保研1人
			cout << a[o].id << " " << a[o].score << "\n";
		}else{
			a[++ now].id = x;
			a[now].score = y;
			for(int j = n; j >= 2; j --){//冒泡排序
				if(a[j].score > a[j - 1].score){
					swap(a[j], a[j - 1]);
				}else if(a[j].score == a[j - 1].score && a[j].id < a[j - 1].id){
					swap(a[j], a[j - 1]);
				}
			}
			int o = max(i / 5, 1);
			cout << a[o].id << " " << a[o].score << "\n";
		}
	}
	return 0;
}

你可能感兴趣的:(算法,c++,开发语言)