例题4-6 师兄帮帮忙(A Typical Homework, UVa 12412)题解——146行代码

欢迎访问我的Uva题解目录哦 https://blog.****.net/richenyunqi/article/details/81149109

题目描述

例题4-6 师兄帮帮忙(A Typical Homework, UVa 12412)题解——146行代码

题意解析

编写一个成绩管理系统(SPMS)。最多有100个学生,每个学生有如下属性。

  • SID:学生编号,包含10位数字。
  • CID:班级编号,为不超过20的正整数。
  • 姓名:不超过10的字母和数字组成,第一个字符为大写字母。名字中不能有空白字符。
  • 4门课程(语文、数学、英语、编程)成绩,均为不超过100的非负整数。
进入SPMS后,应显示主菜单: Welcome to Student Performance Management System (SPMS).

1 - Add
2 - Remove
3 - Query
4 - Show ranking
5 - Show Statistics
0 - Exit

  1. 选择1之后,会出现添加学生记录的提示信息: Please enter the SID, CID, name and four scores. Enter 0 to finish. 然后等待输入。本题保证输入总是合法的,但可能会输入重复SID。在这种情况下,需要输出一行提示: Duplicated SID. 不过名字是可以重复的。你的程序应当不停地打印前述提示信息,直到用户输入单个0。然后应当再次打印主菜单。
  2. 选择2之后,会出现如下提示信息: Please enter SID or name. Enter 0 to finish. 然后等待输入,在数据库中删除能匹配上述SID或者名字的所有学生,并且打印如下信息(xx可以等于0): xx student(s) removed. 你的程序应当不停地打印前述提示信息,直到用户输入单个0,然后再次打印主菜单。
  3. 选择3之后,会出现如下提示信息: Please enter SID or name. Enter 0 to finish. 然后等待输入。如果数据库中没有能匹配上述SID或者名字的学生,什么都不要做;否则输出所有满足条件的学生,按照进入数据库的顺序排列。输出格式和添加的格式相同,但增加3列:年级排名(第一列)、总分和平均分(最后两列)。所有班级中总分最高的学生获得第1名,如果有两个学生并列第2名,则下一个学生的排名为4(而非3)。你的程序应当不停地打印前述提示信息,直到用户输入单个0。然后应当再次打印主菜单。
  4. 选择4之后,会出现如下提示信息: Showing the ranklist hurts students' self-esteem. Don't do that. 然后自动返回主菜单。
  5. 选择5之后,会出现如下提示信息: Chinese Average Score: xx.xx Number of passed students: xx Number of failed students: xx …(为了节约篇幅,此处省略了Mathematics、English和Programming的统计信息) Overall: Number of students who passed all subjects: xx Number of students who passed 3 or more subjects: xx Number of students who passed 2 or more subjects: xx Number of students who passed 1 or more subjects: xx Number of students who failed all subjects: xx 然后自动回到主菜单。
  6. 选择0之后,程序终止。

注意,单科成绩和总分都应格式化为整数,但平均分应恰好保留两位小数。
提示:这个程序适合直接运行,用键盘与之交互,然后从屏幕中看到输出信息。但正因为如此,作为一道算法竞赛的题目,其输出看上去会比较乱。

算法设计

这道题目比较综合,算法思维上的要求并不难,只需按题目要求一步步实现各个功能函数即可。但是因为要注意许多格式上的要求才能AC(事实上这样的格式要求在实际的管理系统中并不多,毕竟大多数的管理系统都是设计了图形用户界面的),所以就显得比较麻烦,比较需要耐心了,不过还是建议大家真正独立地去实现一下这道题目,对编程水平的提高也有很大好处。以下直接附代码。
这道题的测试样例非常有用,如果能做到和测试样例的输出一致,这里的一致包括输出的换行以及空格的数量和位置完全相同,基本就能AC。但是肉眼检测自己程序的输出和样例输出是否一致是很困难,所以在这里推荐一种通过输入输出重定向和windows批处理文件比较程序输出和正确输出的方法,我就是用的这种方法在保证和样例输出完全一致后,提交就AC了。读者也不妨尝试一下。

C++代码

#include<bits/stdc++.h>
using namespace std;
const double limit=1e-6;
struct Student{
    long long SID;
    int CID,score[4],rank=1,totalScore=0;
    double averageScore=0.0;
    string name;
    Student(long long s,int c,string n,int a[]):SID(s),CID(c),name(n){
        for(int i=0;i<4;++i){
            score[i]=a[i];
            totalScore+=a[i];
        }
        averageScore=totalScore/4.0;
    }
};
vector<Student>students;
void split(string&line,vector<string>&s){
    string temp="";
    for(int i=0;i<=line.size();++i)
        if(i==line.size()||line[i]==' '){
            s.push_back(temp);
            temp="";
        }else
            temp+=line[i];
}
void outputMainMenu(){
    printf("Welcome to Student Performance Management System (SPMS).\n\n1 - Add\n"
           "2 - Remove\n3 - Query\n4 - Show ranking\n5 - Show Statistics\n0 - Exit\n\n");
}
void addStudent(){
    printf("Please enter the SID, CID, name and four scores. Enter 0 to finish.\n");
    string input;
    while(getline(cin,input)&&input!="0"){
        vector<string>s;
        split(input,s);
        long long SID=stoll(s[0]);
        if(find_if(students.begin(),students.end(),[SID](const Student&stu){
                   return stu.SID==SID;})!=students.end())
            printf("Duplicated SID.\n");
        else{
            int score[4];
            for(int i=0;i<4;++i)
                score[i]=stoi(s[i+3]);
            students.push_back(Student(SID,stoi(s[1]),s[2],score));
        }
        printf("Please enter the SID, CID, name and four scores. Enter 0 to finish.\n");
    }
}
void removeStudent(){
    printf("Please enter SID or name. Enter 0 to finish.\n");
    string input;
    while(getline(cin,input)&&input!="0"){
        int num=0,SID=-1;
        if(isdigit(input[0]))
            SID=stoll(input);
        for(auto i=students.begin();i!=students.end();){
            if(i->SID==SID||i->name==input){
                i=students.erase(i);
                ++num;
            }else
                ++i;
        }
        printf("%d student(s) removed.\n",num);
        printf("Please enter SID or name. Enter 0 to finish.\n");
    }
}
void queryStudent(){
    printf("Please enter SID or name. Enter 0 to finish.\n");
    vector<pair<int,int>>rank;
    for(int i=0;i<students.size();++i)
        rank.push_back({students[i].totalScore,i});
    sort(rank.begin(),rank.end(),[](const pair<int,int>&a,const pair<int,int>&b){
        return a.first>b.first;});
    for(int i=1;i<rank.size();++i)
        if(rank[i].first==rank[i-1].first)
            students[rank[i].second].rank=students[rank[i-1].second].rank;
        else
            students[rank[i].second].rank=i+1;
    string input;
    while(getline(cin,input)&&input!="0"){
        int SID=-1;
        if(isdigit(input[0]))
            SID=stoll(input);
        for(Student&stu:students)
            if(stu.SID==SID||stu.name==input)
                printf("%d %010lld %d %s %d %d %d %d %d %.2f\n",stu.rank,stu.SID,stu.CID,
                       stu.name.c_str(),stu.score[0],stu.score[1],stu.score[2],
                        stu.score[3],stu.totalScore,stu.averageScore+limit);
        printf("Please enter SID or name. Enter 0 to finish.\n");
    }
}
void showStatistics(){
    printf("Please enter class ID, 0 for the whole statistics.\n");
    int input,pass[5]={0};
    double statistics[4][3]={0.0};
    string subject[4]={
        "Chinese", "Mathematics", "English" , "Programming"
    };
    scanf("%d",&input);
    for(Student&stu:students){
        if(input==0||stu.CID==input){
            int passNum=0;
            for(int i=0;i<4;++i){
                statistics[i][0]+=stu.score[i]*1.0;
                if(stu.score[i]>=60){
                    ++passNum;
                    ++statistics[i][1];
                }else
                    ++statistics[i][2];
            }
            if(passNum>0)
                for(int i=passNum;i>0;--i)
                    ++pass[i];
            else
                ++pass[0];
        }
    }
    for(int i=0;i<4;++i){
        statistics[i][0]/=statistics[i][1]+statistics[i][2];
        printf("%s\nAverage Score: %.2f\nNumber of passed students: %.0f\n"
               "Number of failed students: %.0f\n\n",
               subject[i].c_str(),statistics[i][0]+limit,statistics[i][1],statistics[i][2]);
    }
    printf("Overall:\nNumber of students who passed all subjects: %d\n"
           "Number of students who passed 3 or more subjects: %d\n"
           "Number of students who passed 2 or more subjects: %d\n"
           "Number of students who passed 1 or more subjects: %d\n"
           "Number of students who failed all subjects: %d\n\n",
           pass[4],pass[3],pass[2],pass[1],pass[0]);
}
int main(){
    outputMainMenu();
    int input;
    while(~scanf("%d",&input)&&input!=0){
        getchar();
        if(input==1)    addStudent();
        else if(input==2)   removeStudent();
        else if(input==3)   queryStudent();
        else if(input==4)
            printf("Showing the ranklist hurts students\' self-esteem. Don\'t do that.\n");
        else if(input==5)   showStatistics();
        outputMainMenu();
    }
    return 0;
}