更多PAT题解--acking=you.github.io

题目

OJ平台

题目翻译

实际上就和我们高考录取的过程是一样的。
题目是给出了N个考生的两种成绩(初试和复试)。
每个考生填满K个学校志愿。
然后通过成绩的高低(初试和复试的总和)决定录取的先后顺序。
每个学校有相应的名额限制,如果出现两个初试和复试分数都完全一样的人,则名额不存在限制。
最后要我们输出每个学校的录取名单(以0~N-1代号表示学生)。

我的解题思路

  • 如何模拟这整个录取过程呢?
  1. 把输入的数据先存下来。
  2. 将学生的成绩(总和成绩、初试成绩)和学生编号进行映射。
  3. 通过映射好的数组自定义排序,把总和成绩好的放前面,如果总和成绩相同,则比较初试成绩。
  4. 在前面的人,他拥有优先选择权,通过他这个编号找到他对应的志愿表,并从头到尾录取。(录取通过一个 AdmissionList[i] 数组存下编号为 i 的学校的录取情况)
  5. 通过 AdmissionList[i] 数组存下录取情况的过程中,需要判断这个学校是否已经录满了,如果录取满了,则和它的最低分进行比较,如果和它完全相同则继续录取(不可能比它大,因为本就已经排好序进行录取的)
  6. 最后再通过 AdmissionList 打印结果即可。

代码解读

基本的变量

基本变量

int *schoolN;                               //存储每个学校的限额
int **studentN;                             //存储每个学生的分数和志愿
vector<tuple<int, int, int>> students_sort; //这个只是用来排序的工具
vector<tuple<int, int, int>> *AdmissionList;//存储每个学校的录取名单
/*其实可以把tuple用自定义的数据结构代替,只是C++11标准自带我就直接拿这个过来用了*/

tuple的使用方法

make_tuple()         //可以用于创建tuple对象
get<0~N>(tuple<>)    //0~N表示要访问的下标

存储输入的数据

void Input() {//先把数据存起来再说
    ios::sync_with_stdio(false);
    cin >> N >> M >> K;
    schoolN = new int[M];
    studentN = new int *[N];
    students_sort.resize(N);
    AdmissionList = new vector<tuple<int, int, int>>[M];
    for (int i = 0; i < M; i++) {
        int x;
        cin >> x;
        schoolN[i] = x;
    }
    for (int i = 0; i < N; i++) {
        int n = 2 + K;
        int *t = new int[n];
        for (int j = 0; j < n; j++) {
            int x;
            cin >> x;
            t[j] = x;
        }
        studentN[i] = t;
    }
}

自定义排序模块

对学生通过分数进行排序,决定志愿录取的先后顺序

bool cmp1(tuple<int, int, int> &a, tuple<int, int, int> &b) {//如果总成绩不相同,则成绩高的放前面,否则再看初试成绩
    return (get<0>(a) > get<0>(b)) || (get<0>(a) == get<0>(b) && get<1>(a) > get<1>(b));
}

用于对答案编号按照从小到大输出

bool cmp2(tuple<int, int, int> &a, tuple<int, int, int> &b) {
    return get<2>(a) < get<2>(b);
}

用于判断两个学生是否完全相同和得到学生编号

inline bool IsEqual(tuple<int, int, int> &a, tuple<int, int, int> &b) {
    return get<0>(a) == get<0>(b) && get<1>(a) == get<1>(b);
}

inline int get_val(tuple<int, int, int> &a) {
    return get<2>(a);
}

核心模块--答案的更新

void solve() {
    for (int i = 0; i < N; i++) { //先根据成绩把学生排个序(相当于处理录取时候的顺序)
        for (int j = 2; j < K + 2; j++) {
            int sumP = studentN[i][0] + studentN[i][1];
            int G = studentN[i][0];
            students_sort[i] = make_tuple(sumP, G, i);
        }
    }
    sort(students_sort.begin(), students_sort.end(), cmp1); //排好序后,决定了录取的优先顺序

    //以下为模拟录取过程
    for (int i = 0; i < N; i++) {
        int node = get<2>(students_sort[i]);
        //遍历这个学生的各个志愿
        for (int j = 2; j < K + 2; j++) {
            auto sz = AdmissionList[studentN[node][j]].size();
            if (sz < schoolN[studentN[node][j]]) {
                AdmissionList[studentN[node][j]].push_back(students_sort[i]);
                break;
            } else {
                auto &t = AdmissionList[studentN[node][j]].back();
                if (IsEqual(students_sort[i], t)) {//如果完全相同则破例录取
                    AdmissionList[studentN[node][j]].push_back(students_sort[i]);
                    break;
                }
            }
        }
    }
}

最后--打印答案

void print() {
    for (int i = 0; i < M; i++) {
        auto sz = AdmissionList[i].size();
        sort(AdmissionList[i].begin(), AdmissionList[i].end(), cmp2);//打印前先编号从小到大排序
        for (int j = 0; j < sz; j++) {
            if (j != sz - 1) {
                cout << get_val(AdmissionList[i][j]) << ' ';
            } else cout << get_val(AdmissionList[i][j]);
        }
        if (i != M - 1)
            cout << endl;
    }
}

整合代码提交

效率yyds

#include<bits/stdc++.h>

using namespace std;
int N, M, K;
int *schoolN;                               //存储每个学校的限额
int **studentN;                             //存储每个学生的分数和志愿
vector<tuple<int, int, int>> students_sort; //这个只是用来排序的工具
vector<tuple<int, int, int>> *AdmissionList;//存储每个学校的录取名单
//@输入和更新数据
void Input() {//先把数据存起来再说
    ios::sync_with_stdio(false);
    cin >> N >> M >> K;
    schoolN = new int[M];
    studentN = new int *[N];
    students_sort.resize(N);
    AdmissionList = new vector<tuple<int, int, int>>[M];
    for (int i = 0; i < M; i++) {
        int x;
        cin >> x;
        schoolN[i] = x;
    }
    for (int i = 0; i < N; i++) {
        int n = 2 + K;
        int *t = new int[n];
        for (int j = 0; j < n; j++) {
            int x;
            cin >> x;
            t[j] = x;
        }
        studentN[i] = t;
    }
}

//@更新答案
bool cmp1(tuple<int, int, int> &a, tuple<int, int, int> &b) {
    return (get<0>(a) > get<0>(b)) || (get<0>(a) == get<0>(b) && get<1>(a) > get<1>(b));
}
inline bool IsEqual(tuple<int, int, int> &a, tuple<int, int, int> &b) {
    return get<0>(a) == get<0>(b) && get<1>(a) == get<1>(b);
}
inline int get_val(tuple<int, int, int> &a) {
    return get<2>(a);
}
void solve() {
    for (int i = 0; i < N; i++) { //先根据成绩把学生排个序(相当于处理录取时候的顺序)
        for (int j = 2; j < K + 2; j++) {
            int sumP = studentN[i][0] + studentN[i][1];
            int G = studentN[i][0];
            students_sort[i] = make_tuple(sumP, G, i);
        }
    }
    sort(students_sort.begin(), students_sort.end(), cmp1); //排好序后,就根据这个顺序给学生进行录取

    //以下为模拟录取过程
    for (int i = 0; i < N; i++) {
        int node = get<2>(students_sort[i]);
        for (int j = 2; j < K + 2; j++) {
            auto sz = AdmissionList[studentN[node][j]].size();
            if (sz < schoolN[studentN[node][j]]) {
                AdmissionList[studentN[node][j]].push_back(students_sort[i]);
                break;
            } else {
                auto &t = AdmissionList[studentN[node][j]].back();
                if (IsEqual(students_sort[i], t)) {
                    AdmissionList[studentN[node][j]].push_back(students_sort[i]);
                    break;
                }
            }
        }
    }
}


//@打印答案
bool cmp2(tuple<int, int, int> &a, tuple<int, int, int> &b) {
    return get<2>(a) < get<2>(b);
}
void print() {
    for (int i = 0; i < M; i++) {
        auto sz = AdmissionList[i].size();
        sort(AdmissionList[i].begin(), AdmissionList[i].end(), cmp2);
        for (int j = 0; j < sz; j++) {
            if (j != sz - 1) {
                cout << get_val(AdmissionList[i][j]) << ' ';
            } else cout << get_val(AdmissionList[i][j]);
        }
        if (i != M - 1)
            cout << endl;
    }
}

int main() {
    Input();
    solve();
    print();
    return 0;
}

题外话

  • 讲实话,这个题目感觉就是在写业务代码,实现一个实际功能的。我是比较喜欢这类题型的,感觉这种算法题就比较实用!