PAT甲级 排序题_C++题解

排序题

PAT (Advanced Level) Practice 排序题ios

目录

  • 《算法笔记》 6.9.6 sort()用法
  • 《算法笔记》 4.1 排序题步骤
  • 1012 The Best Rank (25)
  • 1083 List Grades (25)
  • 1137 Final Grading (25)
  • 1141 PAT Ranking of Institutions (25)
  • 1153 Decode Registration Card of PAT (25)

《算法笔记》 6.9.6 sort()

#include<algorithm>
using namespace std;
void sort (first, last, cmp);
// first 首元素地址;last 尾元素地址下一个地址;cmp 比较函数

《算法笔记》 4.1 排序题步骤

1. 相关结构体的定义

struct Student {
    char name[10];
    char id[10];
    int score;
    int rank;
}stu[10000];

2. cmp函数的编写

分数不一样分数高在前,分数相同姓名字典序小在前算法

bool cmp(Student a, Student b){
    return a.score != b.score ? a.score > b.score : strcmp(a.name, b.name) < 0;
}

3. 排名的实现

分数不一样排名不一样,分数相同排名相同占用同一个排位编程

(1) 记录在结构体中
  1. 将数组第一个个体排名记为 1
  2. 遍历剩余个体,若当前个体分数 = 上一个个体分数,则当前个体排名 = 上一个体排名;
  3. 若当前个体分数 != 上一个体分数,则排名 = 数组下标 + 1
stu[0].rank = 1;
for (int i = 1; i < n; i++){
    if (stu[i].score == stu[i-1].score) stu[i].rank = stu[i-1].rank;
    else stu[i].rank = i + 1;
}
(2) 直接输出
int rank = 1;
for (int i = 0; i < n; i++)
    if (i > 0 && stu[i].score != stu[i-1].score)
        rank = i + 1;

1012 The Best Rank (25)

#include<unordered_map>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
struct Student{
    int id, best;
    int score[4], rank[4];
};
int sortby = -1;
bool cmp (Student a, Student b) { return a.score[sortby] > b.score[sortby];};
int main()
{
    int n, m, id;
    scanf("%d%d",&n,&m);
    vector<Student> stu(n+1);
    for (int i = 0; i < n; i++){
        scanf("%d%d%d%d",&stu[i].id,&stu[i].score[1],&stu[i].score[2],&stu[i].score[3]);
        stu[i].score[0] = (stu[i].score[1] + stu[i].score[2] + stu[i].score[3]) / 3;
    }
    for (sortby = 0; sortby < 4; sortby++){
        sort(stu.begin(),stu.end(),cmp);
        stu[0].rank[sortby] = 1;
        for (int i = 1; i < n; i++){
            if (stu[i].score[sortby] != stu[i-1].score[sortby]) stu[i].rank[sortby] = i+1;
            else stu[i].rank[sortby] = stu[i-1].rank[sortby];
        }
    }
    unordered_map<int, int> index;
    for (int i = 0; i < n; i++){
        index.insert(pair<int,int>(stu[i].id,i));
        stu[i].best = 0;
        int minr = stu[i].rank[0];
        for (int j = 1; j < 4; j++){
            if (stu[i].rank[j] < minr){
                stu[i].best = j;
                minr = stu[i].rank[j];
            }
        }
    }
    char symbol[] = "ACME";
    for (int i = 0; i < m; i++){
        scanf("%d",&id);
        if (index.find(id) == index.end()) printf("N/A\n");
        else{
            int best = stu[index[id]].best;
            printf("%d %c\n",stu[index[id]].rank[best], symbol[best]);
        }
    }
    return 0;
}

简化代码(参考柳婼小姐姐的代码

  • 题目中平均分取整数,因此结构体中的分数信息均为 int 型,可用数组表示;同理依据不一样分数进行的排名信息也能够用数组表示。
  • 对四种分数进行排序+排名须要四个不一样的比较函数较为重复,且排序依据在数组中彻底能够用数组下标移动来表示不一样的比较依据。
    • 向 sort() 传入的 cmp() 参数固定不能增长,设置全局变量 sortby
    • 在 cmp() 中依据全局变量变化比较依据,在程序主体控制 sortby 以比较不一样分数
  • 要比较四个不一样的排名选择其中最好的,在结构体中设置变量 best 记录对应分数下标
    • 四种分数用一个简单的选择排序选出 best 进行赋值
    • 最后输出时依据记录的 best 到结构体本身的 rank 数组中输出最好的排名值 及 到字符数组 symbol 中输出对应的科目标识
      • 字符数组初始化问题 -> 笔记:3.5进制转换题 1027 Colors in Mars
  • 本题 id 可用整型表示,因此查找时至关于创建 int->int 的映射,能够直接开大数组作散列查找。
    • 因为以前将 id 设为 string 型,仍然使用 map,因为只用 map 作映射不作排序,可用 unordered_map
    • 注意添加映射关系要在处理完全部排名赋值后,不然sort会打乱排序,映射关系出错。
  • 要对 vector 使用 [] 访问进行赋值必须给出大小,不给大小只能用 push_back 添加元素
简化前代码以下
#include<unordered_map>
#include<vector>
#include<iostream>
#include<algorithm>
using namespace std;
struct Student{
    string id;
    int c, math, eng;
    double avg;
    int r_c, r_math, r_eng, r_avg;
    Student (){}
    Student (string _id, int _c, int _math, int _eng): id(_id), c(_c), math(_math), eng(_eng){
        avg = (c + math + eng) / 3.0;
    }
};
bool cmp_c (Student a, Student b){ return a.c > b.c;}
bool cmp_math (Student a, Student b){ return a.math > b.math;}
bool cmp_eng (Student a, Student b){ return a.eng > b.eng;}
bool cmp_avg (Student a, Student b){ return a.avg > b.avg;}
int main()
{
    int n, m, c, math, eng;
    string id;
    cin >> n >> m;
    vector<Student> stu;
    unordered_map<string, int> index;
    for (int i = 0; i < n; i++){
        cin >> id >> c >> math >> eng;
        stu.push_back(Student(id,c,math,eng));
    }
    sort(stu.begin(),stu.end(),cmp_c);
    stu[0].r_c = 1;
    for (int i = 1; i < n; i++){
        if (stu[i].c == stu[i-1].c) stu[i].r_c = stu[i-1].r_c;
        else stu[i].r_c = i+1;
    }
    sort(stu.begin(),stu.end(),cmp_math);
    stu[0].r_math = 1;
    for (int i = 1; i < n; i++){
        if (stu[i].math == stu[i-1].math) stu[i].r_math = stu[i-1].r_math;
        else stu[i].r_math = i+1;
    }
    sort(stu.begin(),stu.end(),cmp_eng);
    stu[0].r_eng = 1;
    for (int i = 1; i < n; i++){
        if (stu[i].eng == stu[i-1].eng) stu[i].r_eng = stu[i-1].r_eng;
        else stu[i].r_eng = i+1;
    }
    sort(stu.begin(),stu.end(),cmp_avg);
    stu[0].r_avg = 1;
    index.insert(pair<string,int>(stu[0].id,0));
    for (int i = 1; i < n; i++){
        if (stu[i].avg == stu[i-1].avg) stu[i].r_avg = stu[i-1].r_avg;
        else stu[i].r_avg = i+1;
        index.insert(pair<string,int>(stu[i].id,i));
    }
    for (int i = 0; i < m; i++){
        cin >> id;
        if (index.find(id) == index.end()) cout << "N/A\n";
        else{
            int min_r = min(min(min(stu[index[id]].r_c,stu[index[id]].r_math),stu[index[id]].r_eng),stu[index[id]].r_avg);
            cout << min_r << " ";
            if (min_r == stu[index[id]].r_avg) cout << "A\n";
            else if (min_r == stu[index[id]].r_c) cout << "C\n";
            else if (min_r == stu[index[id]].r_math) cout << "M\n";
            else cout << "E\n";
        }
    }
    return 0;
}

1083 List Grades (25)

题目思路

  • 按成绩从大到小排序,排序后过滤输出。
  • 设置变量记录是否找到了值,没找到输出 NONE
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct Student{
    string name, id;
    int grade;
};
bool cmp(Student a, Student b){ return a.grade > b.grade; }
int main()
{
    int n, grade, min, max;
    scanf("%d", &n);
    string name, id;
    vector<Student> list;
    for (int i = 0; i < n; i++){
        cin >> name >> id >> grade;
        list.push_back({name, id, grade});
    }
    sort(list.begin(), list.end(), cmp);
    scanf("%d%d", &min, &max);
    bool empty = true;
    for (int i = 0; i < list.size(); i++){
        if (list[i].grade < min) break;
        if (list[i].grade > max) continue;
        if (empty) empty = false;
        cout << list[i].name << " " << list[i].id << endl;
    }
    if (empty) printf("NONE\n");
    return 0;
}

曾经清奇的脑回路Orz

  • 利用成绩惟一性,以成绩为 key 将姓名学号信息存入 map
  • 利用 map.lower_bound()map.upper_bound() 输出要求信息
#include<iostream>
#include<map>
using namespace std;
int main(){
    map<int,string,greater<int>> records;
    int n, grade, min, max;
    string name, ID;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        cin >> name >> ID >> grade;
        records.insert(pair<int,string>(grade,name + " " + ID));
    }
    scanf("%d%d", &min, &max);
    if (records.lower_bound(max) == records.upper_bound(min))
        cout << "NONE" << endl;
    else
        for (auto it = records.lower_bound(max); it != records.upper_bound(min); ++it)
            cout << it->second << endl;
    return 0;
}

1137 Final Grading (25)

题目思路

  • 将不一样分数分别放到 map 中存储
  • 首要筛选编程分数低于 200 的,取记录编程分数的 map 进行遍历
  • 若编程分数低于 200,或没有登入期末考成绩,不可能合格,continue 跳过
  • 剩余都有期末考成绩,再看是否有期中成绩,如有看是否高于期末,如果则按比例计算总评,若不是则期末分数即为总评分数
  • 依据四舍五入后的总评将学生信息压入结构体容器,注意检查期中考可能无成绩要登入 -1
  • 对结构体数据进行排序后按标准输出
  • 坑点(最后一个测试点):因为要根据总评是否达到 60 决定这个学生是否会加入到及格容器,因此要在判断前进行四舍五入,而非用 double 型做判断后压入容器才四舍五入,这样会损失部分 [59.5,60) 的学生
#include<iostream>
#include<unordered_map>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
struct Student{
    string id;
    int p, mid, final, grade;
};
bool cmp(Student a, Student b) { return a.grade != b.grade ? a.grade > b.grade : a.id < b.id; }
int main()
{
    int p, m, n, score;
    scanf("%d%d%d", &p, &m, &n);
    unordered_map<string,int> program, mid, final;
    string id;
    for (int i = 0; i < p; i++){
        cin >> id >> score;
        if (score <= 900) program.insert({id,score});
    }
    for (int i = 0; i < m; i++){
        cin >> id >> score;
        if (score <= 100) mid.insert({id,score});
    }
    for (int i = 0; i < n; i++){
        cin >> id >> score;
        if (score <= 100) final.insert({id,score});
    }
    vector<Student> list;
    for (auto it: program){
        string id = it.first;
        if (it.second < 200 || final.find(id) == final.end()) continue;
        if (mid.find(id) != mid.end() && mid[id] > final[id]) score = round(mid[id]*0.4 + final[id]*0.6);
        else score = final[id];
        if (score >= 60) list.push_back({id,it.second,mid.find(id)==mid.end()?-1:mid[id],final[id],score});
    }
    sort(list.begin(), list.end(), cmp);
    for (auto it: list) printf("%s %d %d %d %d\n", it.id.c_str(), it.p,it.mid,it.final,it.grade);
    return 0;
}

1141 PAT Ranking of Institutions (25)

题目思路

  • 用两个 map 分别记录每一个学校对应的参考人数和总分
  • map 的 key 值不重复,不须要单独开 set 记录学校 id,只要遍历两个 map 中的一个,将相关信息放到结构体容器中便可
  • 用 sort 对容器排序,因为排名只须要输出不须要记录,能够不记录结构体中而是用变量 rank 记录并输出便可
  • 坑点:因为不一样等级分数换算,总分应当用 double 而非 int 来存,所有计算求和完毕后,压入容器排序前再转换为 int
#include<iostream>
#include<unordered_map>
#include<vector>
#include<algorithm>
using namespace std;
struct School{
    string ID;
    int TWS, Ns;
};
bool cmp (School a, School b){
    return a.TWS != b.TWS ? a.TWS > b.TWS : a.Ns != b.Ns ? a.Ns < b.Ns : a.ID < b.ID;
}
int main()
{
    unordered_map<string,int> ns;
    unordered_map<string,double> tws;
    string id, school;
    int n, score, rank = 1;
    scanf("%d\n", &n);
    for (int i = 0; i < n; i++){
        cin >> id >> score >> school;
        transform(school.begin(), school.end(), school.begin(), ::tolower);
        ns[school]++;
        if (id[0] == 'T') tws[school] += score * 1.5;
        else if (id[0] == 'A') tws[school] += score;
        else tws[school] += score / 1.5;
    }
    vector<School> ranklist;
    for (auto it = ns.begin(); it != ns.end(); it++){
        ranklist.push_back({it->first, (int)tws[it->first], it->second});
    }
    sort(ranklist.begin(), ranklist.end(), cmp);
    printf("%d\n%d %s %d %d\n", ranklist.size(), rank, (ranklist[0].ID).c_str(), ranklist[0].TWS, ranklist[0].Ns);
    for (int i = 1; i < ranklist.size(); i++){
        if (ranklist[i].TWS != ranklist[i-1].TWS) rank = i + 1;
        printf("%d %s %d %d\n", rank, (ranklist[i].ID).c_str(), ranklist[i].TWS, ranklist[i].Ns);
    }
    return 0;
}
  • transform(word.begin(),word.end(),new_word.begin(),op); 要转化为大写, op = ::toupper,因 toupper 是在全局命名空间而非 std 中,因此要加 ::
  • 结构体初始化
    • 顺序初始化:不写构造函数,直接用 {} 按顺序传入参数便可初始化
    • 构造函数初始化:写了构造函数能够用()选择性传参
    • 注意写了构造函数就不能够用顺序初始化了

运行超时

  • 有 map 改成 unordered_map
  • 能用 scanf/printf 的不用 cin/cout
  • 排名只须要输出就不存进结构体,减小一次遍历

1153 Decode Registration Card of PAT (25)

题目思路

  • 将全部考生信息接收到结构体容器中,利用构造函数分别赋值便于后面查询。
  • 第1种 query:直接按分数-准考证号标准将全部级别考生信息一块儿排序,而后遍历时检查符合 query 输入的 level 就输出
  • 第2种 query:能够在输入时计算好,后面直接查询便可
  • 第3种 query:
    • 先遍历一遍全部考生信息,符合输入的日期就将对应的考场号人数++
    • 全部考生检查完毕后遍历全部考场将考生人数不为0的压入vector
    • 依照考生数-考场号标准进行排序,排序后输出
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct CardNumber{
    string cardnum, date;
    char level;
    int site, testeenum, score;
    CardNumber(string _cardnum, int _score): cardnum(_cardnum), score(_score){
        level = _cardnum[0];
        site = stoi(_cardnum.substr(1,3));
        date = _cardnum.substr(4,6);
        testeenum = stoi(_cardnum.substr(10,3));
    }
};
struct SiteNum{
    int site, num;
    SiteNum(int _site, int _num): site(_site), num(_num) {}
};
bool cmp_card(CardNumber a, CardNumber b){ return a.score != b.score ? a.score > b.score : a.cardnum < b.cardnum; }
bool cmp_site(SiteNum a, SiteNum b){ return a.num != b.num ? a.num > b.num : a.site < b.site; }
int main()
{
    int n, m, score, site_tnum[1000] = {0}, site_tscore[1000] = {0};
    string cardnum;
    scanf("%d%d", &n, &m);
    vector<CardNumber> info;
    for (int i = 0; i < n; i++){
        cin >> cardnum >> score;
        info.push_back(CardNumber(cardnum,score));
        site_tnum[info[i].site]++;
        site_tscore[info[i].site] += score;
    }
    sort(info.begin(), info.end(), cmp_card);
    int type, site;
    char level;
    string date;
    for (int i = 0; i < m; i++){
        scanf("%d ", &type);
        bool isempty = true;
        switch(type){
            case 1: 
                scanf("%c",&level);
                printf("Case %d: %d %c\n", i+1, type, level); 
                for (int j = 0; j < n; j++){
                    if (info[j].level == level){
                        isempty = false;
                        cout << info[j].cardnum << " " << info[j].score << endl;
                    }
                }
                if (isempty) printf("NA\n");
                break;
            case 2:
                scanf("%d",&site);
                printf("Case %d: %d %d\n", i+1, type, site); 
                if (!site_tnum[site]) printf("NA\n");
                else printf("%d %d\n", site_tnum[site], site_tscore[site]);
                break;
            case 3:
                cin >> date;
                cout << "Case " << i+1 << ": " << type << " " << date << endl;
                int datesitenum[1000] = {0};
                vector<SiteNum> dsn;
                for (int j = 0; j < n; j++){
                    if (info[j].date == date){
                        isempty = false;
                        datesitenum[info[j].site]++;
                    }
                }
                if (isempty) printf("NA\n");
                else{
                    for (int j = 0; j < 1000; j++) if (datesitenum[j]) dsn.push_back(SiteNum(j,datesitenum[j]));
                    sort(dsn.begin(),dsn.end(),cmp_site);
                    for (int j = 0; j < dsn.size(); j++) printf("%d %d\n", dsn[j].site, dsn[j].num);
                }
                break;
        }
    }
    return 0;
}
  • 注意结构体构造函数初始化表写法
  • cmp函数中一个 if-else 语句可转为三目运算
  • scanf("%c") 会接收空白符,故输入 type 后的空格应写入 scanf 语句,不然用 scanf 接收第1种 query 时,char 型的 level 值没法接收
相关文章
相关标签/搜索