「PAT乙级真题解析」Basic Level 1080 MOOC期终成绩 (问题分析+完整步骤+伪代码描述+提交通过代码)

Source

乙级的题目训练主要用来熟悉编程语言的语法和形成良好的编码习惯和编码规范。从小白开始逐步掌握用编程解决问题。

PAT (Basic Level) Practice 1080 MOOC期终成绩

问题分析

  • 题目给出了三批数据, 分别代表编程成绩, 期中考和期末考成绩。
  • 要求按照给定的公式计算加权总分, 便且给出总分不低于60分的学生信息。
  • 所以, 我们需要做的就是数据存储, 然后进行数据计算, 然后挨个检查进行输出。
  • 由于不同数据是在不同批次给出的, 而且同一个学生代表不同项目成绩需要绑定在一起,
  • 所以涉及到以ID作为唯一标志, 查询ID, 如果ID相同, 则更新该ID下对应的项目成绩。

完整描述步骤

  1. 获取输入: 做了编程题的学生数, 参加了期中考的学生数, 参加了期末考的学生数
  2. 初始化记录器:
    • 成绩信息 = 哈希映射{学生ID -> 学生各项成绩}
  3. 获取输入: 学生ID以及对应的编程题成绩
  4. 对于每一个学生的编程成绩:
    • 成绩信息[学生ID].编程成绩 = 编程成绩
  5. 获取输入: 学生ID以及对应的期中考成绩
  6. 对于每一个学生的期中考成绩:
    • 学生ID 存在于 当前成绩信息中:
      • 成绩信息[学生ID].期中考成绩 = 期中考成绩
  7. 获取输入: 学生ID以及对应的期末考成绩
  8. 对于每一个学生的期末考成绩:
    • 学生ID 存在于 当前成绩信息中:
      • 成绩信息[学生ID].期末考成绩 = 期末考成绩
  9. 计算学生总分, 并将学生成绩进行排序: 先总分降序, 后学号升序
  10. 对于排序后的学生成绩:
    • 如果学生总分大于等于 60:
      • 输出(学生ID, 编程题成绩, 期中考成绩, 期末考成绩)

伪代码描述

  1. get input: program_student_amount, middle_exam_student_amount, final_exam_student_amount;
  2. init recorder:
    • students
  3. for student_index in range(0, program_student_amount):
    • get input: student_ID, program_score
    • students[student_index].ID = program_score;
    • students[student_index].program_score = program_score;
  4. sorted students by student_ID
  5. for case_index in range(0, middle_exam_student_amount):
    • get input: student_ID, middle_exam_score
    • if student_ID found in students(by binary search method):
      • students[student_ID].middle_exam_score = middle_exam_score;
  6. for case_index in range(0, final_exam_student_amount):
    • get input: student_ID, final_exam_score
    • if student_ID found in students(by binary search method):
      • students[student_ID].final_exam_score = final_exam_score;
  7. for student in studens:
    • if student.middle_exam_score > student.final_exam_score:
      • student.total_score = student.middle_exam_score * 0.6 + student.final_exam_score * 0.4
    • else:
      • student.total_score = student.final_exam_score
  8. sort students by total_score and student_ID
  9. for student in students:
    • if student.program_score >= 200:
      • print(student.ID, student.middle_exam_score or -1, student.final_exam_score)

注意事项

  1. 超时问题

    • bsearch
    • 只存储program_score >= 200分的学生数据
    • 因为program必须上200分, 所以如果是program名单里没有的, 但是参加了期中考或期末考的, 可以直接忽略。
  2. 默认值"-1"的问题

    • 最后一个测试点存在学生分数为0
    • 需要提前将分数设置默认值-1

完整提交代码

/*
# 问题分析
题目给出了三批数据, 分别代表编程成绩, 期中考和期末考成绩。
要求按照给定的公式计算加权总分, 便且给出总分不低于60分的学生信息。
所以, 我们需要做的就是数据存储, 然后进行数据计算, 然后挨个检查进行输出。
由于不同数据是在不同批次给出的, 而且同一个学生代表不同项目成绩需要绑定在一起,
所以涉及到以ID作为唯一标志, 查询ID, 如果ID相同, 则更新该ID下对应的项目成绩。

# 完整描述步骤
1. 获取输入: 做了编程题的学生数, 参加了期中考的学生数, 参加了期末考的学生数
2. 初始化记录器:
    - 成绩信息 = 哈希映射{学生ID -> 学生各项成绩}
3. 获取输入: 学生ID以及对应的编程题成绩
4. 对于每一个学生的编程成绩:
    - 成绩信息[学生ID].编程成绩 = 编程成绩
5. 获取输入: 学生ID以及对应的期中考成绩
6. 对于每一个学生的期中考成绩:
    - 学生ID 存在于 当前成绩信息中:
        - 成绩信息[学生ID].期中考成绩 = 期中考成绩
7. 获取输入: 学生ID以及对应的期末考成绩
8. 对于每一个学生的期末考成绩:
    - 学生ID 存在于 当前成绩信息中:
        - 成绩信息[学生ID].期末考成绩 = 期末考成绩
9. 计算学生总分, 并将学生成绩进行排序: 先总分降序, 后学号升序
10. 对于排序后的学生成绩:
    - 如果学生总分大于等于 60:
        - 输出(学生ID, 编程题成绩, 期中考成绩, 期末考成绩)

# 伪代码描述
1. get input: program_student_amount, middle_exam_student_amount, final_exam_student_amount;
2. init recorder:
    - students
3. for student_index in range(0, program_student_amount):
    - get input: student_ID, program_score
    - students[student_index].ID = program_score;
    - students[student_index].program_score = program_score;
4. sorted students by student_ID
5. for case_index in range(0, middle_exam_student_amount):
    - get input: student_ID, middle_exam_score
    - if student_ID found in students(by binary search method):
        - students[student_ID].middle_exam_score = middle_exam_score;
6. for case_index in range(0, final_exam_student_amount):
    - get input: student_ID, final_exam_score
    - if student_ID found in students(by binary search method):
        - students[student_ID].final_exam_score = final_exam_score;
7. for student in studens:
    - if student.middle_exam_score > student.final_exam_score:
        - student.total_score = student.middle_exam_score * 0.6 + student.final_exam_score * 0.4
    - else:
        - student.total_score = student.final_exam_score
8. sort students by total_score and student_ID
9. for student in students:
    - if student.program_score >= 200:
        - print(student.ID, student.middle_exam_score or -1, student.final_exam_score)

# 注意事项
1. 超时问题
    - bsearch
    - 只存储program_score >= 200分的学生数据
    - 因为program必须上200分, 所以如果是program名单里没有的, 但是参加了期中考或期末考的, 可以直接忽略。
    
    
2. 默认值"-1"的问题
    - 最后一个测试点存在学生分数为0
    - 需要提前将分数设置默认值-1
*/

# include<stdio.h>
# include<string.h>
# include <stdlib.h>

typedef struct{
    
      
    char ID[21];
    int program_score;
    int middle_exam_score;
    int final_exam_score;
    int total_score;
} student;

student students[30000];

int cmp(const void* a, const void* b){
    
      
    student student_a = *(student*)a;
    student student_b = *(student*)b;
    return student_a.total_score != student_b.total_score ? student_b.total_score > student_a.total_score : strcmp(student_a.ID, student_b.ID);
}

int cmp_ID(const void* a, const void* b){
    
      
    student student_a = *(student*)a;
    student student_b = *(student*)b;
    return strcmp(student_a.ID, student_b.ID);
}

int calculate_total_score(student student_to_check){
    
      
    if (student_to_check.middle_exam_score > student_to_check.final_exam_score){
    
      
        return student_to_check.middle_exam_score * 0.4 + student_to_check.final_exam_score * 0.6 + 0.5;
    } else {
    
      
        return student_to_check.final_exam_score;
    }
    return 0;
}


int main(){
    
      
    int program_student_amount, middle_exam_student_amount, final_exam_student_amount;
    scanf("%d %d %d", &program_student_amount, &middle_exam_student_amount, &final_exam_student_amount);

    int recorded_student_amount = 0;
    char student_ID[21];
    int score;
    for (int i = 0; i < program_student_amount; i++){
    
      
        scanf("%s %d", student_ID, &score);
        if (score >= 200){
    
      
            strcpy(students[recorded_student_amount].ID, student_ID);
            students[recorded_student_amount].program_score = score;
            students[recorded_student_amount].middle_exam_score = -1;
            students[recorded_student_amount].final_exam_score = -1;
            recorded_student_amount++;
        }
    }

    qsort(students, recorded_student_amount, sizeof(student), cmp_ID);

    for (int i = 0; i < middle_exam_student_amount; i++){
    
      
        scanf("%s %d", student_ID, &score);
        student* found = bsearch(student_ID, students, recorded_student_amount, sizeof(student), cmp_ID);
        if (found != NULL){
    
      
            found->middle_exam_score = score;
        }
    }

    for (int i = 0; i < final_exam_student_amount; i++){
    
      
        scanf("%s %d", student_ID, &score);
        student* found = bsearch(student_ID, students, recorded_student_amount, sizeof(student), cmp_ID);
        if (found != NULL){
    
      
            found->final_exam_score = score;
        }
    }

    for (int i = 0; i < recorded_student_amount; i++){
    
      
        students[i].total_score = calculate_total_score(students[i]);
    }

    qsort(students, recorded_student_amount, sizeof(student), cmp);
    for (int i = 0; i < recorded_student_amount; i++){
    
      
        if (students[i].total_score >= 60){
    
      
            printf("%s %d %d %d %d\n", 
                   students[i].ID, 
                   students[i].program_score, 
                   students[i].middle_exam_score, 
                   students[i].final_exam_score, 
                   students[i].total_score);
        }
    }

    return 0;
}