#P3060. 选修课(100分)
-
1000ms
Tried: 81
Accepted: 47
Difficulty: 6
所属公司 :
华为od
-
算法标签>排序算法
选修课(100分)
题解
该程序的主要目的是分析学生选修课程的情况,找出同时选修两门课程的学生,并按班级和成绩排序输出。输入为两条字符串,分别表示选修课程一和课程二的学生学号及成绩。
思路丰富
- 输入解析:使用
split函数将输入字符串分割成学生学号和成绩,并存入映射中,便于后续查找。 - 交集查找:通过遍历课程一的学生,检查他们是否在课程二的映射中存在,从而找出同时选修两门课程的学生。
- 班级分组:根据学号的前五位进行分组,构建班级与学生之间的映射关系。
- 排序机制:班级先按字典序排列,再根据学生的总成绩和学号进行排序,以确保输出结果的规范性和可读性。
- 结果输出:处理完所有逻辑后,输出每个班级的学生学号,格式要求严谨,确保符合题目要求。
代码分析
-
输入解析:
- 使用
split函数将输入字符串按分号;分割,得到每个学生的学号和成绩。随后,再将每个学生的信息按逗号,分割,将学号和成绩存入映射courseMap中。
- 使用
-
数据存储:
- 使用两个
map<string, int>分别存储课程一和课程二的学生成绩,键为学生学号,值为成绩。 - 使用
map<string, vector<string>>存储同时选修两门课程的学生,键为班级编号,值为该班级的学生学号列表。
- 使用两个
-
交集查找:
- 遍历课程一的学生信息,检查每个学生是否在课程二中存在,找出同时选修两门课程的学生,并将他们按照班级分组。
-
排序:
- 首先按班级编号升序排列班级,然后对每个班级中的学生按总成绩降序、学号升序进行排序。
-
结果输出:
- 按要求格式输出每个班级的编号和对应的学生学号,若没有学生同时选修两门课程,则输出“NULL”。
cpp
#include <bits/stdc++.h>
using namespace std;
// 根据指定分隔符分割字符串
vector<string> split(string &str, char delimiter) {
stringstream ss(str);
string token;
vector<string> results;
while (getline(ss, token, delimiter)) {
results.emplace_back(token);
}
return results;
}
// 解析输入字符串,构建学生成绩映射
void parse(string &str, map<string, int> &courseMap) {
vector<string> studentEntries = split(str, ';'); // 以分号分割每个学生的信息
for (string entry : studentEntries) {
vector<string> info = split(entry, ','); // 以逗号分割学号和成绩
string studentId = info[0];
int score = stoi(info[1]); // 将成绩从字符串转为整数
courseMap[studentId] = score; // 将学号和成绩存入映射中
}
}
int main() {
string input1, input2;
cin >> input1 >> input2; // 读取两条输入字符串
// 存储选修课程一的学生成绩
map<string, int> courseOne;
parse(input1, courseOne);
// 存储选修课程二的学生成绩
map<string, int> courseTwo;
parse(input2, courseTwo);
// 存储同时选修两门课程的学生学号,按班级分组
map<string, vector<string>> classMap;
// 找出同时选修了两门课程的学生
for (const auto &entry : courseOne) {
string studentId = entry.first; // 获取学生学号
// 检查该学生是否也选修了课程二
if (courseTwo.find(studentId) != courseTwo.end()) {
string classId = studentId.substr(0, 5); // 获取班级编号(学号前五位)
classMap[classId].emplace_back(studentId); // 将学号添加到相应班级的列表中
}
}
// 如果没有学生同时选修两门课程,输出NULL
if (classMap.empty()) {
cout << "NULL" << endl;
return 0;
}
vector<string> classIds;
for (const auto &entry : classMap) {
classIds.emplace_back(entry.first); // 存储所有班级编号
}
// 按照班级编号升序排列
sort(classIds.begin(), classIds.end());
// 遍历每个班级
for (const auto &classId : classIds) {
// 按照学生成绩和学号排序
sort(classMap[classId].begin(), classMap[classId].end(), [&courseOne, &courseTwo](string a, string b) {
int scoreA = courseOne[a] + courseTwo[a]; // 计算学生A的总成绩
int scoreB = courseOne[b] + courseTwo[b]; // 计算学生B的总成绩
if (scoreA != scoreB) {
// 按照总成绩降序排列
return scoreA > scoreB;
} else {
// 成绩相同则按学号升序排列
return a < b;
}
});
// 输出班级编号
cout << classId << endl;
// 输出该班级中同时选修两门课程的学生学号
for (int i = 0; i < classMap[classId].size(); i++) {
cout << classMap[classId][i];
if (i < classMap[classId].size() - 1) {
cout << ";"; // 追加分隔符
}
}
cout << endl; // 换行
}
return 0;
}
java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// key为学生学号, value为该学生选修课程一的成绩
HashMap<String, Integer> courseOneScores = new HashMap<>();
parse(scanner.nextLine(), courseOneScores);
// key为学生学号, value为该学生选修课程二的成绩
HashMap<String, Integer> courseTwoScores = new HashMap<>();
parse(scanner.nextLine(), courseTwoScores);
// key为班级编号, value为该班级同时选修两门课程的学生学号集合
HashMap<String, ArrayList<String>> classStudentMap = new HashMap<>();
// 找出同时选修了两门课程的学生学号
for (String studentId : courseOneScores.keySet()) {
if (courseTwoScores.containsKey(studentId)) {
// 班级编号(学号前五位)
String classId = studentId.substring(0, 5);
// 该班级同时选修两门课程的学生学号集合
classStudentMap.putIfAbsent(classId, new ArrayList<>());
classStudentMap.get(classId).add(studentId);
}
}
// 如果没有同时选修两门选修课的学生输出NULL
if (classStudentMap.isEmpty()) {
System.out.println("NULL");
return;
}
// 先按照班级划分,班级编号小的先输出(班级编号字典序升序)
classStudentMap.keySet().stream().sorted(String::compareTo).forEach(classId -> {
classStudentMap.get(classId).sort((a, b) -> {
int totalScoreA = courseOneScores.get(a) + courseTwoScores.get(a);
int totalScoreB = courseOneScores.get(b) + courseTwoScores.get(b);
if (totalScoreA != totalScoreB) {
// 按照两门选修课成绩和的降序
return totalScoreB - totalScoreA;
} else {
// 成绩和相同时按照学号升序
return a.compareTo(b);
}
});
// 先打印班级编号
System.out.println(classId);
// 再打印该班级中同时选修两门课程的学生学号
System.out.println(String.join(";", classStudentMap.get(classId)));
});
}
public static void parse(String input, HashMap<String, Integer> courseMap) {
String[] studentEntries = input.split(";");
for (String studentEntry : studentEntries) {
String[] info = studentEntry.split(",");
String studentId = info[0];
int score = Integer.parseInt(info[1]);
courseMap.put(studentId, score);
}
}
}
python
def parse(input_str, course_map):
student_entries = input_str.split(";")
for entry in student_entries:
student_id, score = entry.split(",")
course_map[student_id] = int(score)
if __name__ == '__main__':
# key为学生学号, value为该学生选修课程一的成绩
courseOneScores = {}
parse(input(), courseOneScores)
# key为学生学号, value为该学生选修课程二的成绩
courseTwoScores = {}
parse(input(), courseTwoScores)
# key为班级编号, value为该班级同时选修两门课程的学生学号集合
classStudentMap = {}
# 找出同时选修了两门课程的学生学号
for studentId in courseOneScores:
if studentId in courseTwoScores:
# 班级编号(学号前五位)
classId = studentId[:5]
# 该班级同时选修两门课程的学生学号集合
classStudentMap.setdefault(classId, [])
classStudentMap[classId].append(studentId)
# 如果没有同时选修两门选修课的学生输出NULL
if len(classStudentMap) == 0:
print("NULL")
else:
# 先按照班级划分,班级编号小的先输出(班级编号字典序升序)
for classId in sorted(classStudentMap.keys()):
# 按照两门选修课成绩和的降序, 成绩和相同时按照学号升序
classStudentMap[classId].sort(key=lambda studentId: (-(courseOneScores[studentId] + courseTwoScores[studentId]), studentId))
# 先打印班级编号
print(classId)
# 再打印该班级中同时选修两门课程的学生学号
print(";".join(classStudentMap[classId]))
题目内容
现有两门选修课,每门选修课都有一部分学生选修,每个学生都有选修课的成绩,需要你找出同时选修了两门选修课的学生,先按照班级进行划分,班级编号小的先输出,每个班级按照两门选修课成绩和的降序排序,成绩相同时按照学生的学号升序排序。
输入描述
第一行为第一门选修课学生的成绩,
第二行为第二门选修课学生的成绩,
每行数据中学生之间以英文分号分隔,每个学生的学号和成绩以英文逗号分隔,
学生学号的格式为8位数字
2位院系编号+入学年份后2位+院系内部1位专业编号+所在班级3位学号
学生成绩的取值范围为[0,100]之间的整数,
两门选修课选修学生数的取值范围为[1-2000]之间的整数。
输出描述
同时选修了两门选修课的学生的学号,如果没有同时选修两门选修课的学生输出NULL,
否则,先按照班级划分,班级编号小的先输出,每个班级先输出班级编号(学号前五位),
然后另起一行输出这个班级同时选修两门选修课的学生学号,学号按照要求排序(按照两门选修课成绩和的降序,成绩和相同时按照学号升序学生之间以英文分号分隔。
样例1
输入
01202021,75;01201033,95;01202008,80;01203006,90;01203088,100
01202008,70;01203088,85;01202111,80;01202021,75;01201100,88
输出
01202
01202008;01202021
01203
01203088
说明
同时选修了两选修课的学生01202021、01202008、01203088,这三个学生两门选修课的成绩和分别为150、150、185,
01202021、01202008属于01202班的学生,按照成绩和降序,成绩相同时按学号升序输出的结果为01202008;01202021,
01203088属于01203班的学生,按照成绩和降序,成绩相同时按学号升序输出的结果为01203088,
01202的班级编号小于01203的班级编号,需要先输出。
样例2
输入
01201022,75;01202033,95;01202018,80;01203006,90;01202066,100
01202008,70;01203102,85;01202111,80;01201021,75;01201100,88
输出
NULL
说明
没有同时选修了两门选修课的学生,输出NULL.