信息学奥赛一本通(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;
}

posted @ 2022-07-31 15:25  不怕困难的博客  阅读(185)  评论(0编辑  收藏  举报  来源