Sort 排序 题库日记

Sort 排序算法

1. 概要

​ 在头文件 < a l g o r i t h m > \color{Orange}<algorithm> <algorithm>中 声明,采用的是成熟的 ”快速排序“ ,默认从小到大排序,时间复杂度为 O (nlogn)

sort(起始位置,终止位置,比较函数(可以没有))

对无序整形数组排序如下

// 对无序整型数组排序

int a[N];

int len = sizeof(a)/sizeof(int);
 
sort(a, a + len); // 从小到大排序
    
sort(a, a + len, greater<int>());// 从大到小排序

对字符排序如下

char a[N];
int len = sizeof(a)/sizeof(char);

sort(a, a + len); // 按 ASCII值 从小到大排序
    
sort(a, a + len, greater<char>()); // 从大到小排序

对结构体排序,由于结构体是没有比较函数的,故我们需要自己写比较函数,或者重载比较运算符

/*比较函数版本*/
struct Node{
    int x, y;
    
}a[N];

bool cmp(int a, int b)
{
    if(a.x != b.x)
        return a.x < b.x;//  如果 a.x 不等于 b.x 就按照 x 从小到大排序
    
    return a.y < b.y;// 如果 x 相等就 按 y 从小到大排序
}

sort(p, p + len, cmp);// 排序,比较函数为 cmp()


/*重载版本*/
struct Node{
    int x, y;
    
     bool operator <(const Node & w)const
    {
        if(x != w.x)
         return x > w.x;
        
        return y > w.y;
        
    }
}p[N];

sort(p, p + len);
    

2. 题目

2.1 单词排序

【题目描述】

​ 输入一行单词,相邻单词之间由一个或多个空格间隔,请按照字典序输出这些单词,要求重复的单词只输出一次(区分大小写)

【输入格式】

​ 第一行为一个整数n,表示有n(1 <= n <= 100 )个单词。随后一行为n个单词,每个单词长度不超过50,单词之间用至少一个空格间隔。数据不含除字母、空格外的其他字符

【输出格式】
按字典序输出这些单词,重复的单词只输出一次

【输入样例】

3
Keep on going

【输出样例】

Keep
going
on

思路

用 string 数组存下来,然后进行 sort 排序

Code

const int N = 110;
string s[N];
int n;

void solve()
{
    cin >> n;
    
    for(int i = 0; i < n; i ++ ) cin >>s[i];
    
    sort(s, s + n);
     n = unique(s, s + n) - s;
    for(int i = 0; i < n; i ++ )
        cout << s[i] << "\n";
}

2.2 志愿者选拔

【题目描述】
学院选拔志愿者,面试分数线根据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第m×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低面试分数线的所有选手
请编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩

【输入格式】

​ 第一行为两个整数 n和m ( 5 <= b <= 5000, 3 <= m <= n),其中n表示报名参加笔试的选手总数,m表示计划录取的志愿者人数。输入数据保证 m×150% 向下取整后小于等于n

【输出格式】
第一行为两个整数,分别表示面试分数线和进入面试的选手的实际人数
从第二行开始,每行两个整数,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同则按报名号由小到大的顺序输出

【输入样例】

6 3
1000 90
3239 88
2390 95
7231 84
1005 95
1001 88

【输出样例】

88 5
1005 95
2390 95
1000 90
1001 88
3239 88

【样例说明】
m×150%=3×150%=4.5,向下取整后为4。保证4个人进入面试的分数线为88,但因为88有重分,所以所有成绩大于等于88的选手都可以进入面试,故进入面试的选手的实际人数为5

思路

​ 读入学生信息,按分数从高到低排序,若分数相同则按照学号从小到大排,计算出录取的人数后,统计学生中分数大于等于录取分数的人数,根据题目格式输出即可

const int N = 5010;

struct Node{
    int num, score;
}a[N];

bool cmp(struct Node a, struct Node b)
{
    if(a.score != b.score)
        return a.score > b.score;
    return a.num < b.num;
}

int n, m;// 学生人数,应该录取的人数
int sum, s; // 录取的实际人数,录取分数线
void solve()
{
    scanf("%d%d", &n, &m);

    for(int i = 1; i <= n; i ++ )
    {
         scanf("%d%d", &a[i].score, &a[i].num);
    }
    sort(a + 1, a + n + 1, cmp); // 排序
    
    m = m * 3/2;
    for(int i = 1; i <= n; i ++ )
    {
        if(i == m)
          s = a[i].score;
        if(a[i].score >= s)
          sum ++;
    }
    
    printf("%d %d\n", m, s);// 录取的实际人数, 录取分数线
    for(int i = 1; i <= n; i ++ )
    {
        if(a[i].score >= s) // 大于等于录取分数的学生信息
            printf("%d %d\n", a[i].num, a[i].score);
    }
}

2.3 奖学金

【题目描述】
学校打算为学习成绩优秀的前5名学生发奖学金。每个学生都有3门课的成绩:语文、数学及英语。先按总分从高到低排序,如果两个学生总分相同,再按语文成绩从高到低排序;如果两个学生总分和语文成绩都相同,那么规定学号小的学生排在前面。这样每个学生的排序是唯一确定的,试按排名顺序输出前5名学生的学号和总分

【输入格式】
第一行为一个正整数n( 6 <= n <= 300),表示该校参加评选的学生人数。第二行到第n+1行,每行有3个以空格间隔的数字,每个数字都为0~100。第j行的3个数字依次表示学号为j-1的学生的语文、数学及英语的成绩。每个学生的学号按照输入顺序编号为 l~n (恰好是输入数据的行号减1)

【输出格式】
输出共有5行,每行两个正整数(以空格间隔),依次表示前5名学生的学号和总分

【输入样例】

6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98

【输出样例】

6 265
4 264
3 258
2 244
1 237

思路

​ 读入学生信息,按照题目要求排序后,输出前 5 名即可

Code

struct student{
	
	int num;
	int chinese, math, english;
	int score;
	
}a[N];

bool cmp(struct student a, struct student b)
{
	if(a.score != b.score)
	 	return a.score > b.score;
	if(a.chinese != b.chinese)
		return a.chinese > b.chinese;
	
	return a.num < b.num;
	
}

int n;
void solve()
{
	scanf("%d",&n);
	
	for(int i = 1; i <= n ; i ++ )
	{
		scanf("%d%d%d", &a[i].chinese, &a[i].math, &a[i].english);
		a[i].score = a[i].chinese + a[i].math + a[i].english;
		a[i].num = i;
	}
	sort(a + 1, a + n + 1, cmp);
	
	for(int i = 1; i <= n && i <= 5; i ++ )
	{
		printf("%d %d\n", a[i].num, a[i].score);
	}
	
}

2.4 导弹拦截系统

【题目描述】
有一种新的导弹拦截系统,凡是与它的距离不超过其工作半径的导弹都能够被它成功拦截。当工作半径为0时,则能够拦截与它位置恰好相同的导弹。但每套导弹拦截系统每天只能设定一次工作半径,而当天的使用代价,就是所有系统工作半径的平方和

​ 某天,雷达捕捉到敌国的导弹来袭。由于该系统尚处于试验阶段,因此只有两套系统投入工作。如果现在的要求是拦截所有的导弹,请计算这一天的最小使用代价

【输入格式】
第一行包含4个整数 x1 、y1 、x2 、y2 ,每两个整数之间以一个空格间隔,表示这两套导弹拦截系统的坐标分别为(x1 ,y1 )、(x2 ,y2 )

​ 第二行包含一个整数N,表示有N 颗导弹。接下来为N 行,每行有两个整数x、y,中间以一个空格间隔,表示一颗导弹的坐标(x,y),不同导弹的坐标可能相同

【输出格式】
输出只有一行,包含一个整数,即当天的最小使用代价

【数据范围】

对于100%的数据,1 <= n <= 100000 ,且所有坐标分量的绝对值都不超过1 000

【算法提示】
两个点(x1 ,y1 )、(x2 ,y2 )之间距离的平方是 ( x 1 - x 2 ) 2 + ( y 1 - y 2 ) 2 (x1 -x2 )^2 + (y1 -y2 )^2 (x1x2)2+(y1y2)2
两套系统工作半径 r1 、r2 的平方和,是指 r1 、r2 分别取平方后再求和,即 r 1 2 + r 2 2 r_1^ 2 +r_2^2 r12+r22

【输入样例1】

0 0 10 0
2
-3 3
10 0

【输出样例1】

18

【样例说明1】
样例1中要拦截所有导弹,在满足最小使用代价的前提下,两套系统工作半径的平方分别为18和0

【输入样例2】

0 0 6 0
5
-4 -2
-2 3
4 0
6 -2
9 1

【输出样例2】

30

思路

​ 如下图所示,设导弹拦截系统为 a 和 b, 计算出所有导弹到 a 和 b 的距离 ,并按照到 a 的距离从小到大排序。假如选择一点 k到 a 的距离作为 a的半径,那么排在k点之后的点都能被 a击落,而k点之前的点只能被b击落,则b的半径即是前 k -1 个点到 b 的最大半径

在这里插入图片描述

Code

const int N = 10010;

struct Node{
	int da, db;
}a[N];

bool cmp(struct Node a , struct Node b)
{
	return a.da > b.da;
}

int n;// 导弹的数量
void  solve()
{
	int x1, y1, x2, y2;
	scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
	scanf("%d", &n);
	
	for(int i = 1; i <= n; i ++ )
	{
		int x, y;
        
		scanf("%d%d", &x, &y);
		a[i].da = pow(x1 - x, 2) + pow(y1 - y, 2);
		a[i].db = pow(x2 - x, 2) + pow(y2 - y, 2);

	}
	
	sort(a + 1, a + n + 1, cmp);
    
    // 枚举半径
	int  r_b = -0x3f3f3f;
	int  ans = 0x3f3f3f;

	for(int i = 1; i <= n; i ++ )
	{
		int r_a = a[i].da;// 选择当前到 a 的距离作为半径
		r_b = max(r_b, a[i - 1].db);// 前 i - 1 个到 b 的最大半径
		
		int r2 = r_a + r_b;// 代价为 两者半径平方之和
		ans = min(ans, r2);
		
	}
	
	printf("%d\n", ans);
} 

【参考资料】
【1】 《编程竞赛宝典:C++语言和算法入门》张新华著,人民邮电出版社,ISBN:978-7-115-55461-1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值