1085 PAT单位排行 (25 分)
题意描述:
每次 PAT 考试结束后,考试中心都会发布一个考生单位排行榜。本题就请你实现这个功能。
输入格式:
输入第一行给出一个正整数 N(≤10^5 ),即考生人数。随后 N 行,每行按下列格式给出一个考生的信息:
准考证号 得分 学校
其中准考证号是由 6 个字符组成的字符串,其首字母表示考试的级别:B代表乙级,A代表甲级,T代表顶级
;得分是 [0, 100] 区间内的整数;学校是由不超过 6 个英文字母组成的单位码(大小写无关)。注意:题目保证每个考生的准考证号是不同的。
输出格式:
首先在一行中输出单位个数。随后按以下格式非降序输出单位的排行榜:
排名 学校 加权总分 考生人数
其中排名是该单位的排名(从 1 开始);学校是全部按小写字母输出的单位码;加权总分定义为乙级总分/1.5 + 甲级总分 + 顶级总分*1.5的整数部分;考生人数是该属于单位的考生的总人数。
学校首先按加权总分排行。如有并列,则应对应相同的排名,并按考生人数升序输出。如果仍然并列,则按单位码的字典序输出。
输入样例:
10
A57908 85 Au
B57908 54 LanX
A37487 60 au
T28374 67 CMU
T32486 24 hypu
A66734 92 cmu
B76378 71 AU
A47780 45 lanx
A72809 100 pku
A03274 45 hypu
输出样例:
5
1 cmu 192 2
1 au 192 3
3 pku 100 1
4 hypu 81 2
4 lanx 81 2
解题思路:
Alice: 题目倒是讲的挺明白的,就是输入有10000个,估计用Python写又要超时,有得凉凉了。┐(・o・)┌
Bob: 对啊,用C++ 的话,还得处理怎么从校名这个字符串映射到 成绩和 学生总数这个问题。也不知道 C++ 有没有字典啊,还是对C++ 模板库不哦,用C++处理字符串我也不熟。
Alice: 那你快学呀,这样吧,你先用Python 写,如果实在过不去,我去看看别人用C++ 怎么写的。ヾ(◍°∇°◍)ノ゙
Bob: ∠(°ゝ°) 【(╯▽╰) 】
代码:
- Bob’s Python
Version ?
from functools import cmp_to_key
def main():
N = int(input())
# 接收输入的正整数 N
global data
data = {}
for x in range(N):
# 依次接收N个考生的 数据
ID, score, school = (z for z in input().split())
# 元组拆包
school = school.lower()
data.setdefault(school, [0, 0])
# number of stu, total score
if ID[0] == 'B':
data[school][1] += float(score) / 1.5
elif ID[0] == 'A':
data[school][1] += float(score)
else:
data[school][1] += float(score) * 1.5
# 将这位考生的分数 做变化后 加到对应的学校那儿
data[school][0] += 1
# 对应的学校那儿的考生人数加一
for school in data:
data[school][1] = int(data[school][1])
# 排序之前,根据题意只保留 该学校成绩的整数部分
answer = sorted(data, key=cmp_to_key(compare), reverse=True)
# 根据题意排序
pre_rank = rank = 1
# pre_rank 是排好序的列表中前一项的排名
# rank 是当前项的排名
print(len(answer))
# 输出学校总数
school = answer[0]
print("{} {} {} {}".format(rank, school,
data[school][1], data[school][0]))
# 输出排名第一的学校的信息
for index in range(1, len(answer)):
if data[answer[index]][1] == data[answer[index - 1]][1]:
rank = pre_rank
# 总分与前一任学校相等
else:
pre_rank = rank = index + 1
# 否则得到一个新的排名
school = answer[index]
print("{} {} {} {}".format(rank, school,
data[school][1], data[school][0]))
def compare(a, b):
# a, b 都是 data 的 key, 且 a 在前 b在后。返回负数时交换data[a], data[b]
if data[a][1] != data[b][1]:
# 总分不等
return data[a][1] - data[b][1]
else:
# 总分相等,学校人数不等
if data[a][0] != data[b][0]:
return data[b][0] - data[a][0]
else:
# 总分相等,学校人数也相等
if a > b:
# 校名a 的字典序 大于 校名b的字典序
return -1
else:
return 1
if __name__ == '__main__':
main()
- Alice’s Bravo C++ Version:
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
// 定义一个结构体,用来存储最后要输出的信息
struct node{
string school;
int score;
int cnt;
};
// c++ sort函数cmp参数要写成 返回值是bool类型的函数
// 返回False 时交换元素的位置
bool compare(node a, node b){
if (a.score != b.score){
return a.score > b.score;
// 按成绩降序
}else if (a.cnt != b.cnt){
return a.cnt < b.cnt;
// 按学校人数升序
}else{
return a.school < b.school;
// 按校名字典序 升序
}
}
int main(){
int N;
int score;
string ID, school;
scanf("%d", &N);
// 接收输入的正整数 N
map<string, int> cnt;
map<string, double> scores;
// c++ 中的map 类似有 Python 中的字典,不同的是,仅仅能建立两种数据类型之间的映射。
//(as far as I know)
for(int i=0; i<N; ++i){
cin >> ID;
scanf("%d", &score);
cin >> school;
// 输入某人的ID, 成绩, 校名
for(int j=0; j<school.length(); ++j){
school[j] = tolower(school[j]);
}
//把校名转换成小写
if(ID[0] == 'B'){
scores[school] += double(score) / 1.5;
}else if(ID[0] == 'T'){
scores[school] += double(score) * 1.5;
}else{
scores[school] += double(score);
}
// 把该生的成绩加到对应的学校那儿去
cnt[school] += 1;
// 对应的学校那儿的学生人数也加一
}
/* two methods to Traversing the map
map <string, double>::iterator iter;
iter = scores.begin();
while (iter != scores.end()){
cout << iter->first << " " << iter->second << endl;
iter ++;
}
for(map<string, int>::iterator iter = cnt.begin(); iter != cnt.end(); iter++){
cout << iter->first << " " << iter->second << endl;
}
*/
vector<node> score_and_cnt;
// 由于最终一共有多少学校是未知的,我们使用vector(动态数组)来存储
for(map<string, int>::iterator iter = cnt.begin(); iter != cnt.end(); iter++){
node temp = {iter->first, int(scores[iter->first]), iter->second};
score_and_cnt.push_back(temp);
}
// 将某个学校的 校名,成绩,人数,依次取出组成一条node类型的数据 ,存入score_and_cnt中
sort(score_and_cnt.begin(), score_and_cnt.end(), compare);
// 按题意对 score_and_cnt 排序
// one method to Traversing the vector
int pre_score = -1, rank = 0;
cout << score_and_cnt.size() << endl;
// 输出学校总数
for(int i=0; i<score_and_cnt.size(); ++i){
if(score_and_cnt[i].score != pre_score){
// 当前学校分数与前一个学校的总分不等,则排名更新
rank = i + 1;
pre_score = score_and_cnt[i].score;
}
// 否则,排名,前一名的总分都不变
cout << rank << " " << score_and_cnt[i].school << " "
<< score_and_cnt[i].score << " " << score_and_cnt[i].cnt << endl;
// 输出排名,校名,分数,人数
}
return 0;
}
易错点:
- Python 容易超时,毕竟10000条数据,还要排序。咱也不知道还能不能再优化一下,还能不能再快一点。(¦3」∠)__(¦3」∠)。
- 保留总分的整数部分需要先求出总分之后再保留整数部分,不能先保留了整数部分再求出来的总分。
总结:
- Bob’s Python
Version ?
- Alice’s Bravo C++ Version: