「PAT乙级真题解析」Basic Level 1095 解码PAT准考证 (问题分析+完整步骤+伪代码描述+提交通过代码)

题设给定一组数据, 然后再给定一组查询, 要求根据查询要求输出对应的数据. 由于本题涉及到查询/统计, 所以核心在于数据的存储与目标数据的查询。 由于输出的信息涉及到按考场和按考生分类统计数据, 所以需要分别建立考生和考场两个模型。

#算法#数据结构#需求分析#c语言#pat考试

Table of Contents

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

PAT (Basic Level) Practice 1095 解码PAT准考证

问题分析

  • 题设给定一组数据, 然后再给定一组查询, 要求根据查询要求输出对应的数据.
  • 由于本题涉及到查询/统计, 所以核心在于数据的存储与目标数据的查询。
  • 由于输出的信息涉及到按考场和按考生分类统计数据, 所以需要分别建立考生和考场两个模型。

完整描述步骤

  1. 获取输入: 考生人数, 查询次数
  2. 获取输入: 所有考生的准考证号和成绩(并从准考证号中提取级别, 考场编号, 考试日期, 考生编号)
  3. 将考生信息根据先成绩降序, 后准考证号升序的顺序排列
  4. 读取输入: 各个查询指令
  5. 对于每一个指令:
    • 如果是要求输出指定级别考生成绩的指令1:

      • 初始化记录器: 参考了指定级别考试的考生人数 = 0
      • 依次检查排序后的各个考生信息:
        • 如果该考生的考试级别等于指定的考试级别:
          • 参考了指定级别考试的考生人数++
          • 输出"{该考生准考证号} {该考生成绩}"
      • 如果 参考了指定级别考试的考生人数 等于 0:
        • 输出"NA"
    • 如果是要求输出给定考场信息的指令2:

      • 初始化记录器:
        • 目标考场的考生人数 = 0
        • 目标考场的所有考生分数和 = 0
      • 依次检查各个考生的信息:
        • 如果该考生的考场编号等于指定的考试编号:
          • 目标考场的考生人数++
          • 目标考场的所有考生分数和 += 该考生考试成绩
      • 如果 目标考场的考生人数 等于 0:
        • 输出"NA"
      • 否则:
        • 输出"{目标考场的考生人数} {目标考场的所有考生分数和}"
    • 如果是要求输出指定日期各考场学生人数的指令3:

      • 初始化记录器:
        • 各个考场信息 = {}
        • 在指定日期参加考试的考生人数 = 0
      • 依次访问各个考生的信息:
        • 如果 该考生参加考试的日期 等于 指定考试日期:
          • 在指定日期参加考试的考生人数++
          • 各个考场信息[该考生的考场编号].考生人数++
      • 将统计到的考场信息按照考生人数降序排列
      • 输出各个考场信息

伪代码描述

  1. get input: student_amount, query_amount
  2. get input: all students' ID and score
  3. sort students by score descendingly, when scores is same by alphabet order ascendingly
  4. get input: all commands of queries
  5. for each query:
    • if command of query is equal to 1:
      • init recorder: total_amount = 0
      • for each student:
        • if student.level == target_level:
          • print("{student.ID} {student.score}")
          • total_amount++;
      • if total_amount == 0:
        • print("NA")
    • if command of query is equal to 2:
      • init recorder:
        • total_amount = 0;
        • total_student_amount = 0;
        • total_student_score = 0;
      • for each studen:
        • if student.exam_location == target_location:
          • total_student_amount++;
          • total_student_score += student.score;
      • if total_amount == 0:
        • print("NA")
      • else:
        • print("{total_student_amount} {total_student_score}")
    • if command of query is equal to 3:
      • init recorder:
        • total_amount = 0
        • student_amount_of_locations = {}
      • for each student:
        • if student.exam_date == target_date:
          • total_amount++
          • student_amount_of_locations[student.exam_location]++
      • if total_amount == 0:
        • print("NA")
      • else:
        • sort locations by student amount descendingly
        • for location in locations:
          • print("{location.number} {location.student_amount}")

注意事项

  1. 测试点2: 类型为1, 查询的等级没有考生的情况;
  2. 测试点3: 多次类型为3(查询某个日期考场人数分布情况);
  3. 测试点1, 测试点4: 类型为3, 查询结果为空的情况;

完整提交代码

/*
# 问题分析
题设给定一组数据, 然后再给定一组查询, 要求根据查询要求输出对应的数据.
由于本题涉及到查询/统计, 所以核心在于数据的存储与目标数据的查询。
由于输出的信息涉及到按考场和按考生分类统计数据, 所以需要分别建立考生和考场两个模型。
 
# 完整描述步骤
1. 获取输入: 考生人数, 查询次数
2. 获取输入: 所有考生的准考证号和成绩(并从准考证号中提取级别, 考场编号, 考试日期, 考生编号)
3. 将考生信息根据先成绩降序, 后准考证号升序的顺序排列
4. 读取输入: 各个查询指令
5. 对于每一个指令:
    - 如果是要求输出指定级别考生成绩的指令1:
        - 初始化记录器: 参考了指定级别考试的考生人数 = 0
        - 依次检查排序后的各个考生信息:
            - 如果该考生的考试级别等于指定的考试级别:
                - 参考了指定级别考试的考生人数++
                - 输出"{该考生准考证号} {该考生成绩}"
        - 如果 参考了指定级别考试的考生人数 等于 0:
            - 输出"NA"
        
    - 如果是要求输出给定考场信息的指令2:
        - 初始化记录器:
            - 目标考场的考生人数 = 0
            - 目标考场的所有考生分数和 = 0
        - 依次检查各个考生的信息:
            - 如果该考生的考场编号等于指定的考试编号:
                - 目标考场的考生人数++
                - 目标考场的所有考生分数和 += 该考生考试成绩
        - 如果 目标考场的考生人数 等于 0:
            - 输出"NA"
        - 否则:
            - 输出"{目标考场的考生人数} {目标考场的所有考生分数和}"
    - 如果是要求输出指定日期各考场学生人数的指令3:
        - 初始化记录器:
            - 各个考场信息 = {}
            - 在指定日期参加考试的考生人数 = 0
        - 依次访问各个考生的信息:
            - 如果 该考生参加考试的日期 等于 指定考试日期:
                - 在指定日期参加考试的考生人数++
                - 各个考场信息[该考生的考场编号].考生人数++
        - 将统计到的考场信息按照考生人数降序排列
        - 输出各个考场信息
 
# 伪代码描述
1. get input: student_amount, query_amount
2. get input: all students' ID and score
3. sort students by score descendingly, when scores is same by alphabet order ascendingly
4. get input: all commands of queries
5. for each query:
    - if command of query is equal to 1:
        - init recorder: total_amount = 0
        - for each student:
            - if student.level == target_level:
                - print("{student.ID} {student.score}")
                - total_amount++;
        - if total_amount == 0:
            - print("NA")
    - if command of query is equal to 2:
        - init recorder:
            - total_amount = 0;
            - total_student_amount = 0;
            - total_student_score = 0;
        - for each studen:
            - if student.exam_location == target_location:
                - total_student_amount++;
                - total_student_score += student.score;
        - if total_amount == 0:
            - print("NA")
        - else:
            - print("{total_student_amount} {total_student_score}")
    - if command of query is equal to 3:
        - init recorder:
            - total_amount = 0
            - student_amount_of_locations = {}
        - for each student:
            - if student.exam_date == target_date:
                - total_amount++
                - student_amount_of_locations[student.exam_location]++
        - if total_amount == 0:
            - print("NA")
        - else:
            - sort locations by student amount descendingly
            - for location in locations:
                - print("{location.number} {location.student_amount}")
 
# 注意事项
1. 测试点2: 类型为1, 查询的等级没有考生的情况;
2. 测试点3: 多次类型为3(查询某个日期考场人数分布情况);
3. 测试点1, 测试点4: 类型为3, 查询结果为空的情况;
 
*/
 
 
# include<stdio.h>
# include<string.h>
 
typedef struct student{
    char ID[14];
    char level;
    int exam_location;
    int exam_date;
    int exam_number;
    int score;
} student;
 
typedef struct location{
    int number;
    int student_amount;
} location;
 
 
int cmp(const void *a, const void *b){
    student A = *(student*)a;
    student B = *(student*)b;
 
    return A.score != B.score ? A.score < B.score : strcmp(A.ID, B.ID);
}
 
int cmp_location(const void *a, const void *b){
    location A = *(location *)a;
    location B = *(location *)b;
    
    return A.student_amount != B.student_amount ? A.student_amount < B.student_amount : A.number > B.number;
}
 
int extract_number(char *ID, int start, int end){
    int result = 0;
    for (int i = start; i < end; i++){
        result = result * 10 + (ID[i] - '0');
    }
    return result;
}
 
void read_all_student_info(student *students, int student_amount){
    char ID[14];
    int score;
    for (int i = 0; i < student_amount; i++){
        scanf("%s %d", ID, &score);
        strcpy(students[i].ID, ID);
        students[i].score = score;
        students[i].level = ID[0];
        students[i].exam_location = extract_number(ID, 1, 4);
        students[i].exam_date = extract_number(ID, 4, 10);
        students[i].exam_number = extract_number(ID, 10, 13);
    }
}
 
void print_student_info_of_given_level(student *students, int student_amount, char level){
    int total_amount = 0;
    for (int j = 0; j < student_amount; j++){
        if (students[j].level == level){
            printf("%s %d\n", students[j].ID, students[j].score);
            total_amount++;
        }
    }
    if (total_amount == 0){
        printf("NA\n");
    }
}
 
void print_student_amount_and_total_score_of_given_location(student *students, int student_amount, int target_location){
    int total_amount = 0, total_score = 0;
    for (int j = 0; j < student_amount; j++){
        if (students[j].exam_location == target_location){
            total_amount++;
            total_score += students[j].score;
        }
    }
    if (total_amount){
        printf("%d %d\n", total_amount, total_score);
    } else {
        printf("NA\n");
    }
}
 
void print_each_location_info_in_given_date(student *students, int student_amount, int target_date){
    location locations[1000];
    for (int i = 0; i < 1000; i++){
        locations[i].number = i;
        locations[i].student_amount = 0;
    }
 
    int total_amount = 0;
    for (int j = 0; j < student_amount; j++){
        if (students[j].exam_date == target_date){
            locations[students[j].exam_location].student_amount++;
            total_amount++;
        }
    }
    
    if (total_amount == 0){
        printf("NA\n");
    } else {
        qsort(locations, 1000, sizeof(location), cmp_location);
        for (int j = 0; j < 1000; j++){
            if (locations[j].student_amount){
                printf("%d %d\n", locations[j].number, locations[j].student_amount);
            }
        }
    }
}
 
 
int main(){
    int student_amount, query_amount;
    scanf("%d %d", &student_amount, &query_amount);
 
    student students[student_amount];
    read_all_student_info(students, student_amount);
 
    qsort(students, student_amount, sizeof(student), cmp);
    int type;
    char command[7];
    for (int i = 0; i < query_amount; i++){
        scanf("%d %s", &type, command);
        printf("Case %d: %d %s\n", i+1, type, command);
        if (type == 1){
            print_student_info_of_given_level(students, student_amount, command[0]);
        } else if (type == 2){
            print_student_amount_and_total_score_of_given_location(students, student_amount, atoi(command));
        } else if (type == 3){
            print_each_location_info_in_given_date(students, student_amount, atoi(command));
        }
    }
 
    return 0;
}
「PAT乙级真题解析」Basic Level 1095 解码PAT准考证 (问题分析+完整步骤+伪代码描述+提交通过代码) | 生活糖果