更多PAT题解--acking=you.github.io
题目
题目翻译
实际上就和我们高考录取的过程是一样的。
题目是给出了N个考生的两种成绩(初试和复试)。
每个考生填满K个学校志愿。
然后通过成绩的高低(初试和复试的总和)决定录取的先后顺序。
每个学校有相应的名额限制,如果出现两个初试和复试分数都完全一样的人,则名额不存在限制。
最后要我们输出每个学校的录取名单(以0~N-1代号表示学生)。
我的解题思路
- 如何模拟这整个录取过程呢?
- 把输入的数据先存下来。
- 将学生的成绩(总和成绩、初试成绩)和学生编号进行映射。
- 通过映射好的数组自定义排序,把总和成绩好的放前面,如果总和成绩相同,则比较初试成绩。
- 在前面的人,他拥有优先选择权,通过他这个编号找到他对应的志愿表,并从头到尾录取。(录取通过一个
AdmissionList[i]
数组存下编号为 i 的学校的录取情况) - 通过
AdmissionList[i]
数组存下录取情况的过程中,需要判断这个学校是否已经录满了,如果录取满了,则和它的最低分进行比较,如果和它完全相同则继续录取(不可能比它大,因为本就已经排好序进行录取的) - 最后再通过
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; }
题外话
- 讲实话,这个题目感觉就是在写业务代码,实现一个实际功能的。我是比较喜欢这类题型的,感觉这种算法题就比较实用!