信息学奥赛一本通(C++)基础算法之数据排序
问题 A: 【一本通基础排序】【例2.2】车厢重组
[题目描述]
在一个旧式的火车站旁边有一座桥,其桥面可以绕河中心的桥墩水平旋转。一个车站的职工发现桥的长度最多能容纳两节车厢,如果将桥旋转180度,则可以把相邻两节车厢的位置交换,用这种方法可以重新排列车厢的顺序。于是他就负责用这座桥将进站的车厢按车厢号从小到大排列。他退休后,火车站决定将这一工作自动化,其中一项重要的工作是编一个程序,输入初始的车厢顺序,计算最少用多少步就能将车厢排序。
输入
有两行数据,第一行是车厢总数N(不大于10000),第二行是N个不同的数表示初始的车厢顺序。
输出
一个数据,是最少的旋转次数。
样例输入
4 4 3 2 1
样例输出
6
#include<bits/stdc++.h>
using namespace std;
int a[100010], r[100010];
int n,ans;
void asort(int begin, int end)
{
if(begin == end)
return;
int mid = (begin + end) / 2;
asort(begin, mid);
asort(mid + 1, end);
int x = mid + 1, y = begin, z = begin;
while(x <= end && y <= mid)
if(a[x] < a[y])
{
ans += mid - y + 1;
r[z++] = a[x++];
}
else
r[z++] = a[y++];
while(x <= end)
r[z++] = a[x++];
while(y <= mid)
r[z++] = a[y++];
for(int i = begin; i <= end; i++)
a[i] = r[i];
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i];
asort(1, n);
cout << ans;
return 0;
}
问题 B: 【一本通基础排序】【例2.5】求逆序对
[题目描述]
给定一个序列a_1,a_2,…,a_n,如果存在i<j并且a_i>a_j,那么我们称之为逆序对,求逆序对的数目。
输入
第一行为n,表示序列长度,接下来的n行,第i+1行表示序列中的第i个数。
输出
所有逆序对总数。
样例输入
4 3 2 3 2
样例输出
3
#include<bits/stdc++.h>
using namespace std;
long long a[100001], r[100001];
long long n, ans;
void asort(long long begin, long long end)
{
if(begin == end)
return;
long long mid = (begin + end) / 2;
asort(begin, mid);
asort(mid + 1, end);
long long x = mid + 1, y = begin, z = begin;
while(x <= end && y <= mid)
if(a[x] < a[y])
{
ans += mid - y + 1;
r[z++] = a[x++];
}
else
r[z++] = a[y++];
while(x <= end)
r[z++] = a[x++];
while(y <= mid)
r[z++] = a[y++];
for(long long i = begin;i <= end;i++)
a[i] = r[i];
}
int main()
{
cin >> n;
for(long long i = 1; i <= n; i++)
cin >> a[i];
asort(1, n);
cout << ans;
return 0;
}
问题 C: 【一本通基础排序】谁考了第k名
[题目描述]
在一次考试中,每个学生的成绩都不相同,现知道了每个学生的学号和成绩,求考第k名学生的学号和成绩。
输入
第一行有两个整数,分别是学生的人数n(1≤n≤100),和求第k名学生的k(1≤k≤n)。
其后有n行数据,每行包括一个学号(整数)和一个成绩(浮点数),中间用一个空格分隔。
输出
输出第k名学生的学号和成绩,中间用空格分隔。(注:请用%g输出成绩)
样例输入
5 3 90788001 67.8 90788002 90.3 90788003 61 90788004 68.4 90788005 73.9
样例输出
90788004 68.4
#include <bits/stdc++.h>
using namespace std;
struct node{
int id;
float grade;
};
bool cmp(node a, node b){
return a.grade>b.grade;
}
int main(){
int n, m;
node a[111];
cin >> n >> m;
for(int i = 0;i<n;++i)
cin >> a[i].id >> a[i].grade;
sort(a,a+n,cmp);
printf("%d %g\n",a[m-1].id,a[m-1].grade);
return 0;
}
问题 D: 【一本通基础排序】奇数单增序列
[题目描述]
给定一个长度为N(不大于500)的正整数序列,请将其中的所有奇数取出,并按升序输出。
输入
第1行为 N;
第2行为 N 个正整数,其间用空格间隔。
输出
增序输出的奇数序列,数据之间以逗号间隔。数据保证至少有一个奇数。
样例输入
10 1 3 2 6 5 4 9 8 7 10
样例输出
1,3,5,7,9
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define re(x) scanf("%d",&x)
int n;
int a[1000];
int cnt;
int main()
{
re(n);
for(int i=1;i<=n;++i)
{
int temp;
re(temp);
if(temp%2)
a[++cnt]=temp;
}
sort(a+1,a+cnt+1);
for(int i=1;i<cnt;i++)
printf("%d,",a[i]);
printf("%d\n",a[cnt]);
return 0;
}
问题 E: 【一本通基础排序】成绩排序
[题目描述]
给出班里某门课程的成绩单,请你按成绩从高到低对成绩单排序输出,如果有相同分数则名字字典序小的在前。
输入
第一行为n (0 < n < 20),表示班里的学生数目;
接下来的n行,每行为每个学生的名字和他的成绩, 中间用单个空格隔开。名字只包含字母且长度不超过20,成绩为一个不大于100的非负整数。
输出
把成绩单按分数从高到低的顺序进行排序并输出,每行包含名字和分数两项,之间有一个空格。
样例输入
4 Kitty 80 Hanmeimei 90 Joey 92 Tim 28
样例输出
Joey 92 Hanmeimei 90 Kitty 80 Tim 28
#include <bits/stdc++.h>
using namespace std;
struct jkl
{
string s;
int store;
}a[21];
int n;
bool cmp(jkl x, jkl y){
if(x.store > y.store)return 1;
else if(x.store < y.store)return 0;
else return x.s < y.s;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i].s >> a[i].store;
}
sort(a + 1, a + n + 1, cmp);
for(int i = 1; i <= n; i++)
{
cout << a[i].s << " " << a[i].store << endl;
}
return 0;
}
自于互联网,如有侵权请来信告知,accoders@aliyun.com邮箱
问题 G: 【一本通基础排序】分数线划定
[题目描述]
世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的150%划定,即如果计划录取m名志愿者,则面试分数线为排名第m×150%(向下取整)名的选手的分数,而最终进入面试的选手为笔试成绩不低于面试分数线的所有选手。
现在就请你编写程序划定面试分数线,并输出所有进入面试的选手的报名号和笔试成绩。
输入
第一行,两个整数$n,m(5 ≤ n ≤ 5000,3 ≤ m ≤ n)$,中间用一个空格隔开,其中$n$ 表示报名参加笔试的选手总数,$m$ 表示计划录取的志愿者人数。输入数据保证$m×150%$向下取整后小于等于$n$。
第二行到第 $n+1$ 行,每行包括两个整数,中间用一个空格隔开,分别是选手的报名号$k(1000 ≤ k ≤ 9999)$和该选手的笔试成绩$s(1 ≤ s ≤ 100)$。数据保证选手的报名号各不相同。
输出
第一行,有两个整数,用一个空格隔开,第一个整数表示面试分数线;第二个整数为进入面试的选手的实际人数。
从第二行开始,每行包含两个整数,中间用一个空格隔开,分别表示进入面试的选手的报名号和笔试成绩,按照笔试成绩从高到低输出,如果成绩相同,则按报名号由小到大的顺序输出。
样例输入
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
#include <bits/stdc++.h>
using namespace std;
struct node{
int k;
int s;
}p[10000], mid, t;
int main()
{
int n, m, q;
int i, j;
int count = 0;
scanf("%d%d", &n, &m);
for(i = 0; i < n; i++)
scanf("%d%d", &p[i].k, &p[i].s);
for(i = 0; i < n; i++)
for(j = i + 1; j < n; j++)
if(p[i].s < p[j].s){
t = p[i];
p[i] = p[j];
p[j] = t;
}else if(p[i].s == p[j].s){
if(p[i].k > p[j].k){
t = p[i];
p[i] = p[j];
p[j] = t;
}
}
q = m * 1.5;
for(i = 0; i < n; i++)
if(p[i].s >= p[q - 1].s)
count++;
else
break;
printf("%d %d\n", p[q - 1].s, count);
for(i = 0; i < count; i++)
printf("%d %d\n", p[i].k, p[i].s);
return 0;
}
问题 H: 【一本通基础排序】整数奇偶排序
[题目描述]
给定10个整数的序列,要求对其重新排序。排序要求:
1.奇数在前,偶数在后;
2.奇数按从大到小排序;
3.偶数按从小到大排序。
输入
输入一行,包含10个整数,彼此以一个空格分开,每个整数的范围是大于等于0,小于等于100。
输出
按照要求排序后输出一行,包含排序后的10个整数,数与数之间以一个空格分开。
样例输入
4 7 3 13 11 12 0 47 34 98
样例输出
47 13 11 7 3 0 4 12 34 98
#include <bits/stdc++.h>
using namespace std;
int a[20], b[110], c[110];
int main()
{
int n = 10;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
if(a[i] % 2 == 0)
{
b[a[i]]++;
}
else
{
c[a[i]]++;
}
}
for(int i = 99; i >= 1; i -= 2)
{
while(c[i] > 0)
{
cout << i << " ";
c[i]--;
}
}
for(int i = 0; i <= 100; i+= 2)
{
while(b[i] > 0){
cout << i << " ";
b[i]--;
}
}
}
问题 I: 【一本通基础排序】合影效果
[题目描述]
小云和朋友们去爬香山,为美丽的景色所陶醉,想合影留念。如果他们站成一排,男生全部在左(从拍照者的角度),并按照从矮到高的顺序从左到右排,女生全部在右,并按照从高到矮的顺序从左到右排,请问他们合影的效果是什么样的(所有人的身高都不同)?
输入
第一行是人数n(2 ≤ n ≤ 40,且至少有1个男生和1个女生)。
后面紧跟n行,每行输入一个人的性别(男male或女female)和身高(浮点数,单位米),两个数据之间以空格分隔。
输出
n个浮点数,模拟站好队后,拍照者眼中从左到右每个人的身高。每个浮点数需保留到小数点后2位,相邻两个数之间用单个空格隔开。
样例输入
6 male 1.72 male 1.78 female 1.61 male 1.65 female 1.70 female 1.56
样例输出
1.65 1.72 1.78 1.70 1.61 1.56
#include <bits/stdc++.h>
using namespace std;
double a[1000];
string b[1000];
int main()
{
int n, i, k, j;
bool first = true;
cin >> n;
for(i = 1; i <= n; i++) cin >> b[i] >> a[i];
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n - i; j++)
{
if(a[j] > a[j + 1])
{
swap(a[j], a[j + 1]);
swap(b[j], b[j + 1]);
}
}
}
for(i = 1; i <= n; i++)
if(b[i] == "male") printf("%0.2lf ", a[i]);
for(i = n; i >= 1; i--)
if(b[i] == "female") printf("%0.2lf ", a[i]);
return 0;
}
问题 J: 【一本通基础排序】病人排队
[题目描述]
病人登记看病,编写一个程序,将登记的病人按照以下原则排出看病的先后顺序:
1.老年人(年龄 >= 60岁)比非老年人优先看病。
2.老年人按年龄从大到小的顺序看病,年龄相同的按登记的先后顺序排序。
3.非老年人按登记的先后顺序看病。
输入
第1行,输入一个小于100的正整数,表示病人的个数;
后面按照病人登记的先后顺序,每行输入一个病人的信息,包括:一个长度小于10的字符串表示病人的ID(每个病人的ID各不相同且只含数字和字母),一个整数表示病人的年龄,中间用单个空格隔开。
输出
按排好的看病顺序输出病人的ID,每行一个。
样例输入
5 021075 40 004003 15 010158 67 021033 75 102012 30
样例输出
021033 010158 021075 004003 102012
#include "bits/stdc++.h"
using namespace std;
struct huanzhe {
string id;
int age;
} hz1[301], hz60[301], hz59[301]; //hz60[301] >=60岁,hz59[301] <60岁 ;
// hz hz60[301], hz59[301]; //hz60[301] >=60岁,hz59[301] <60岁
int cnt1 = 5, cnt60 = 0, cnt59 = 0; //cnt1总数, cnt60 计数>=60岁,cnt59 计数<60岁
//插入排序 20220310
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> hz1[i].id >> hz1[i].age;
}
cnt1 = n;
// hz1[] = {{"id001", 29}, {"id002", 60}, {"id003", 70}, {"id004", 66}, {"id005", 36}};
//提出>=60岁的患者,插入排序;
//其余患者不需排序,按输入顺序排序。
for(int n = 1; n <= cnt1; n++) {
if(hz1[n].age >= 60) {
cnt60++;
for(int i = 1; i <= cnt60; i++) {
if(hz1[n].age > hz60[i].age) {//插入到当前i位置
for(int j = cnt60; j >= i; j--) {//1. 原i位置及以后数据全部依次后移一个位置
hz60[j + 1].id = hz60[j].id;
hz60[j + 1].age = hz60[j].age;
}
hz60[i].id = hz1[n].id; //2. 插入到当前i位置
hz60[i].age = hz1[n].age;
break;//3. 插入数据完成,退出
}
// else if(hz1[n].age == hz60[i].age) {//下次比对
// }
// else {//下次比对
// }
// hz60[cnt60].age = hz1[n].age;
//hz60[cnt60].id = hz1[n].id;
}
// //将元数据再hz1数组中标记、去除
// hz1[n].id = "";
// hz1[n].age = 100;
}
}
for(int i = 1; i <= cnt60; i++) {
cout << hz60[i].id << endl;
}
for(int i = 1; i <= cnt1; i++) {
if(hz1[i].age < 60)
cout << hz1[i].id << endl;
}
return 0;
}
问题 L: 【一本通基础排序】单词排序
[题目描述]
输入一行单词序列,相邻单词之间由1个或多个空格间隔,请按照字典序输出这些单词,要求重复的单词只输出一次。(区分大小写)
输入
一行单词序列,最少1个单词,最多100个单词,每个单词长度不超过50,单词之间用至少1个空格间隔。数据不含除字母、空格外的其他字符。
输出
按字典序输出这些单词,重复的单词只输出一次。
样例输入
She wants to go to Peking University to study Chinese
样例输出
Chinese Peking She University go study to wants
#include <bits/stdc++.h>
using namespace std;
string s[100001];
int len;
int main()
{
int i, n = 0, t, j, k;
string ss;
while(cin >> ss)
{
n++;
s[n] = ss;
}
for(i = 1; i <= n - 1; i++)
{
for(j = i + 1; j <= n; j++)
if(s[i] > s[j]) swap(s[i], s[j]);
}
for(i = 1; i <= n; i++)
if(s[i - 1] != s[i]) cout << s[i] << endl;
return 0;
}
问题 M: 【一本通基础排序】出现次数超过一半的数
[题目描述]
给出一个含有n(0 < n ≤ 1000)个整数的数组,请找出其中出现次数超过一半的数。数组中的数大于-50且小于50。
输入
第一行包含一个整数n,表示数组大小;
第二行包含n个整数,分别是数组中的每个元素,相邻两个元素之间用单个空格隔开。
输出
如果存在这样的数,输出这个数;否则输出no。
样例输入
3 1 2 2
样例输出
2
#include <bits/stdc++.h>
using namespace std;
int n;
int b[1001], x;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> x;
b[x + 100]++;
if(b[x + 100] > (n / 2))
{
printf("%d", x);
return 0;
}
}
printf("no");
return 0;
}
问题 N: 【一本通基础排序】统计字符数
[题目描述]
给定一个由a-z这26个字符组成的字符串,统计其中哪个字符出现的次数最多。
输入
输入包含一行,一个字符串,长度不超过1000。
输出
输出一行,包括出现次数最多的字符和该字符出现的次数,中间以一个空格分开。如果有多个字符出现的次数相同且最多,那么输出ascii码最小的那一个字符。
样例输入
abbccc
样例输出
c 3
#include <bits/stdc++.h>
using namespace std;
int a[30];
char s[1100];
int main()
{
int i, len, max = -1, j;
memset(a, 0, sizeof(a));
scanf("%s", s);
len = strlen(s);
for(i = 0; i < len; i++) a[s[i] - 'a']++;
for(i = 0; i < 26; i++)
if(a[i] > max)
{
j = i;
max = a[i];
}
printf("%c %d",'a' + j, max);
return 0;
}