新手刷题网站,快速入门!洛谷
排序
4.5
【深基9.例1】选举学生会
题目描述
学校正在选举学生会成员,有 n ( n ≤ 999 ) 名候选人,每名候选人编号分别从 1 到 n,现在收集到了 m (m ≤ 2000000 ) 张选票,每张选票都写了一个候选人编号。现在想把这些堆积如山的选票按照投票数字从小到大排序。
输入格式
输入 n和 m以及 m个选票上的数字。
输出格式
求出排序后的选票编号。
输入样例
5 10
2 5 2 2 5 2 2 2 1 2
输出样例
1 2 2 2 2 2 2 2 5 5
思路
上去就无脑冒泡,结果TLE感动了,本题正确思路是采用计数排序
代码
#include<iostream>
using namespace std;
int a[2000];
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i<m;i++){
int t;
cin>>t;
a[t]++;
}
int flag=0;
for(int i=1;i<=n;i++){
for(int j=0;j<a[i];j++){
if(flag++) cout<<' ';
cout<<i;
}
}
return 0;
}
【模板】快速排序
题目描述
略
思路
每次迭代确保k值左边 <= k ,k 值右边 >= k, 即,每轮下来,确定一个k值的位置,快排模板是一定要记住的!!
这里简单记录一下位运算,>> 代表 右移
比如 6 的二进制为 0110,将其右移一位,变成 0011,即 3,因此 >>1 可以理解为 /2
代码
#include<iostream>
using namespace std;
int a[100010];
void quick_sort(int q[], int l, int r)
{
//如果数组<=一个数,无需排序
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
quick_sort(a,0,n-1);
for(int i=0;i<n;i++){
if(i<n-1){
printf("%d ",a[i]);
}else{
printf("%d",a[i]);
}
}
return 0;
}
【深基9.例4】求第 k 小的数
题目描述
略
思路
无论是求第k小数还是第k大数,都是快排的延伸,我们知道快排一轮可以确定一个数的位置,进行迭代的过程,我们只需要知道第k小数在该数字的左边还是右边,然后迭代单边即可,记住快排模板,加以改进即可。
代码
#include <iostream>
using namespace std;
const int N = 5000010;
int q[N];
//该模板是从第1个数开始的
int quick_sort(int q[], int l, int r, int k)
{
if (l >= r) return q[l];
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j){
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
if (j - l + 1 >= k) return quick_sort(q, l, j, k);
else return quick_sort(q, j + 1, r, k - (j - l + 1));
}
int main(){
int n, k;
scanf("%d%d", &n, &k);
//题目要求从第0个数开始,因此k++
k++;
//如果求第k大数,只需赋值k为如下代码即可
//k = n-k+1;
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
cout << quick_sort(q, 0, n - 1, k) << endl;
return 0;
}
[NOIP2006 普及组] 明明的随机数
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 1 到 1000 之间的随机整数 ( N ≤ 100 ),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
思路
本题分为两步,第一步去重复,第二步排序,去重在输入过程中,遍历数组判断该数字是否存在即可
代码
#include <iostream>
using namespace std;
const int N = 110;
int q[N];
//排序直接用快排模板
int quick_sort(int q[], int l, int r)
{
if (l >= r) return q[l];
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j){
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
int main(){
int n;
int len=1;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ){
int t;
scanf("%d", &t);
for(int j=0;j<len;j++){
//如果输入的数字在数组中已存在,跳出本次循环
if(q[j]==t) break;
//否则在数组尾部插入该数字,并调整数组长度+1,确保数组尾部总有一个值为0的数字等待插入
else if(q[j]==0){
q[j]=t;
len++;
break;
}
}
}
quick_sort(q, 0, len-2);
//数组实际长度为len-1,在数字插入操作时,为了确保数组尾部总有一个值为0的数字,数组长度故意+1
printf("%d\n", len-1);
for (int i = 0; i < len-1; i ++ ){
if(i<len-2) printf("%d ", q[i]);
else printf("%d", q[i]);
}
return 0;
}
4.8
[NOIP2007 普及组] 奖学金
题目描述
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。
输入样例
6 //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
思路
本题与 帮贡排序 相似,在做帮贡排序时,我用两个数组做的,比较繁琐,本题采用结构体做法。首先题目要求:先按总成绩排序、再按语文成绩排序、再按学号排序。帮贡题是,先按帮贡排序,再按等级、再按经验,所以两道题很相似。本题中使用了sort大法 + 自定义比较函数,真香,具体步骤见代码。自定义比较函数,这里提供了两种方案,if else 和 三目表达式。
代码
#include <iostream>
#include<algorithm>
using namespace std;
struct Students{
//学号
int num;
//语数英
int c,m,e;
//总分
int sum;
};
Students s[310];
//比较函数
bool swp(Students s1,Students s2){
//if else写法
//总成绩
if(s1.sum>s2.sum) return true;
//语文成绩
else if(s1.sum==s2.sum&&s1.c>s2.c) return true;
//学号
else if(s1.sum==s2.sum&&s1.c==s2.c&&s1.num<s2.num) return true;
else return false;
//三目表达式写法
//return s1.sum>s2.sum?s1.sum>s2.sum:(s1.sum==s2.sum&&s1.c>s2.c?s1.c>s2.c:(s1.sum==s2.sum&&s1.c==s2.c&&s1.num<s2.num?s1.num<s2.num:0));
//return 0;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&s[i].c,&s[i].m,&s[i].e);
s[i].num = i;
s[i].sum = s[i].c + s[i].m + s[i].e;
}
sort(s+1,s+1+n,swp);
for(int i=1;i<=5;i++){
printf("%d %d\n",s[i].num,s[i].sum);
}
return 0;
}