第一部分 实验要求
【问题描述】
参加运动会的 n 个学校编号为 1~n。比赛分成 m 个男子项目和 w 个女子项目,项目编
号分别为 1~m 和 m+1~m+W。由于各项目参加人数差别较大,有些项目取前五名,得分
顺序为 7,5,3,2,1;还有些项目只取前三名,得分顺序为 5,3,2。写一个统计程序产
生各种成绩单和得分报表。
【基本要求】
产生各学校的成绩单,内容包括各校所取得的每项成绩的项目号、名次(成绩)、姓名和
得分;产生团体总分报表,内容包括校号、男子团体总分、女子团体总分和团体总分。
【测试数据】
对于 n=4,m=3,w=2,编号为奇数的项目取前五名,编号为偶数的项目取前三名,设
计一组实例数据。
【实现提示】
可以假设,n≤20,m≤30,w≤20,姓名长度不超过 20 个字符。每个项目结束时,将
其编号、类型符(区分取前五名还是前三名)输入,并按名次顺序输入运动员姓名、校名(和成
绩)。
【选作内容】
允许用户指定某项目采取其他名次取法。
第二部分 实现代码
以下代码使用C++实现。
#include<iostream>
#include<cstring>
#include<cstdlib>
#define Past_Dream super_FW
using namespace std;
typedef struct record{
int event_num;
int competitor_rank;
string competitor_name;
int competitor_score;
}state_record;
int main(){
int school_num , boys_event_num , girls_event_num;
cout << "Please enter the number of participating schools:";
cin >> school_num;
cout << "Please enter the number of events for boys:";
cin >> boys_event_num;
cout << "Please enter the number of events for girls:";
cin >> girls_event_num;
int total_event_num = boys_event_num + girls_event_num;
state_record report_card[school_num+1][6*total_event_num];
int p[school_num+1] = {0} , boys_score[school_num+1][2] , girls_score[school_num+1][2] , total_score[school_num+1][2] ;
for(int i = 1 ; i <= school_num ; i++){
p[i] = 1;
boys_score[i][0] = 0;
boys_score[i][1] = i;
girls_score[i][0] = 0;
girls_score[i][1] = i;
total_score[i][0] = 0;
total_score[i][1] = i;
}
int temp_event_num , temp_type , temp_sch , new_rule_temp;
int new_rule[1000] = {0};
string temp_name;
char input_temp[1024];
for(int i = 1 ; i <= total_event_num ; i++){
cout << "Please enter the event number:";
cin >> temp_event_num;
cout << "Please enter the event type(1 for classical Top 5 scoring competition, 2 for classical Top 3 scoring competition, 3 for new rule):";
cin >> temp_type;
switch (temp_type){
case 1:
for(int j = 1 ; j <= 5 ; j++){
cout << "Please enter the school number of the rank " << j << " competitor:";
cin >> temp_sch;
cout << "Please enter the name of the rank " << j << " competitor:";
cin >> temp_name;
report_card[temp_sch][p[temp_sch]].event_num = temp_event_num;
report_card[temp_sch][p[temp_sch]].competitor_name = temp_name;
report_card[temp_sch][p[temp_sch]].competitor_rank = j;
switch(j){
case 1:
report_card[temp_sch][p[temp_sch]].competitor_score = 7;
total_score[temp_sch][0] += 7;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 7;
else girls_score[temp_sch][0] += 7;
break;
case 2:
report_card[temp_sch][p[temp_sch]].competitor_score = 5;
total_score[temp_sch][0] += 5;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 5;
else girls_score[temp_sch][0] += 5;
break;
case 3:
report_card[temp_sch][p[temp_sch]].competitor_score = 3;
total_score[temp_sch][0] += 3;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 3;
else girls_score[temp_sch][0] += 3;
break;
case 4:
report_card[temp_sch][p[temp_sch]].competitor_score = 2;
total_score[temp_sch][0] += 2;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 2;
else girls_score[temp_sch][0] += 2;
break;
case 5:
report_card[temp_sch][p[temp_sch]].competitor_score = 1;
total_score[temp_sch][0] += 1;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 1;
else girls_score[temp_sch][0] += 1;
break;
default:
cout << "Error, Please contact the administrator." << endl;
break;
}
p[temp_sch]++;
}
break;
case 2:
for(int j = 1 ; j <= 3 ; j++){
cout << "Please enter the school number of the rank " << j << " competitor:";
cin >> temp_sch;
cout << "Please enter the name of the rank " << j << " competitor:";
cin >> temp_name;
report_card[temp_sch][p[temp_sch]].event_num = temp_event_num;
report_card[temp_sch][p[temp_sch]].competitor_name = temp_name;
report_card[temp_sch][p[temp_sch]].competitor_rank = j;
switch(j){
case 1:
report_card[temp_sch][p[temp_sch]].competitor_score = 5;
total_score[temp_sch][0] += 5;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 5;
else girls_score[temp_sch][0] += 5;
break;
case 2:
report_card[temp_sch][p[temp_sch]].competitor_score = 3;
total_score[temp_sch][0] += 3;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 3;
else girls_score[temp_sch][0] += 3;
break;
case 3:
report_card[temp_sch][p[temp_sch]].competitor_score = 2;
total_score[temp_sch][0] += 2;
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += 2;
else girls_score[temp_sch][0] += 2;
break;
default:
cout << "Error, Please contact the administrator." << endl;
break;
}
p[temp_sch]++;
}
break;
case 3:
cout << "Please enter how many of the top places can score in this competition:" ;
cin >> new_rule_temp;
cout << "Please enter the scores for each position in order of ranking.You can separate the two scores with spaces or carriage returns:";
for(int j = 1 ; j <= new_rule_temp ; j++){
cin >> new_rule[j];
if(j!= 1 && new_rule[j] > new_rule[j-1]){
fgets(input_temp, sizeof(input_temp), stdin);
cout << "Are you sure your input is correct? If you confirm, please enter to skip, otherwise, please enter any character and press enter to re-enter this group of data from the first place.";
if (fgets(input_temp, sizeof(input_temp), stdin)) {
if (input_temp[0] != '\n'){
j = 0;
cout << "Please enter the scores for each position in order of ranking.You can separate the two scores with spaces or carriage returns:";
}
}
}
}
for(int j = 1 ; j <= new_rule_temp ; j++){
cout << "Please enter the school number of the rank " << j << " competitor:";
cin >> temp_sch;
cout << "Please enter the name of the rank " << j << " competitor:";
cin >> temp_name;
report_card[temp_sch][p[temp_sch]].event_num = temp_event_num;
report_card[temp_sch][p[temp_sch]].competitor_name = temp_name;
report_card[temp_sch][p[temp_sch]].competitor_rank = j;
report_card[temp_sch][p[temp_sch]].competitor_score = new_rule[j];
total_score[temp_sch][0] += new_rule[j];
if(temp_event_num <= boys_event_num) boys_score[temp_sch][0] += new_rule[j];
else girls_score[temp_sch][0] += new_rule[j];
p[temp_sch]++;
}
break;
default:
cout << "Error, Please check the input." << endl;
break;
}
}
for(int i = 1 ; i <= school_num ; i++){
cout << "School " << i << ":\n";
cout << "Boys team score: " << boys_score[i][0] << "\n";
cout << "Girls team score: " << girls_score[i][0] << "\n";
cout << "Total score: " << total_score[i][0] << "\n";
for(int j = 1 ; j < p[i] ; j++){
cout << "Event " << report_card[i][j].event_num << " " << report_card[i][j].competitor_name << " " << report_card[i][j].competitor_rank << " " << report_card[i][j].competitor_score << "\n";
}
cout << "--------------------------------------------------------" << endl;
}
for(int i = 1 ; i <= school_num ; i++){
for(int j = i + 1 ; j <= school_num ; j++){
if(boys_score[i][0] < boys_score[j][0]){
swap(boys_score[i][0], boys_score[j][0]);
swap(boys_score[i][1], boys_score[j][1]);
}
if(girls_score[i][0] < girls_score[j][0]){
swap(girls_score[i][0], girls_score[j][0]);
swap(girls_score[i][1], girls_score[j][1]);
}
if(total_score[i][0] < total_score[j][0]){
swap(total_score[i][0], total_score[j][0]);
swap(total_score[i][1], total_score[j][1]);
}
}
}
cout << "Boys' ranking:" << endl;
for(int i = 1 ; i <= school_num ; i++){
cout << "School " << boys_score[i][1] << " Boys Team: " << boys_score[i][0] << "\n";
}
cout << "--------------------------------------------------------" << endl;
cout << "Girls' ranking:" << endl;
for(int i = 1 ; i <= school_num ; i++){
cout << "School " << girls_score[i][1] << " Girls Team: " << girls_score[i][0] << "\n";
}
cout << "--------------------------------------------------------" << endl;
cout << "Total ranking:" << endl;
for(int i = 1 ; i <= school_num ; i++){
cout << "School " << total_score[i][1] << " Total: " << total_score[i][0] << "\n";
}
cout << "--------------------------------------------------------" << endl;
return 0;
}
第三部分 实验报告
一、需求分析
本程序的主要任务是根据各个项目的比赛情况,以学校为单位输出比赛情况的记录,并统计每个学校的男子总分、女子总分和团体总分。
输入形式:用户按照屏幕提示选择相应的操作。在数据录入时,按每个项目比赛结束的排名情况,依次输入(项目号、类型符、运动员名字、所在学校)。
异常处理:对没有数据录入的情况能做出相应处理,比如当没有数据录入时,无法执行生成成绩单或报表的操作。
输出形式:依次按照学校的编号输出该校的比赛情况记录,以及按照学校编号输出该校的男子总分、女子总分及团体总分。
程序执行的命令包括:1.数据录入 2.产生成绩单 3.产生报表
二、概要设计
为了实现上述程序功能,我们用顺序表(数组)来表示比赛记录。为此定义一个抽象数据类型List来管理这些记录,并提供一系列基本操作。以下是详细的ADT定义:
ADT List:
数据对象:D = {ai | ai ∈ ElemSet, i = 1, 2, ..., n, n >= 0},其中 `ElemSet` 是所有可能的比赛记录的集合。
数据关系:R1 = {<ai-1, ai> | ai-1, ai ∈ D, i = 2, ..., n}表示线性表中的元素是按顺序排列的。
基本操作:
1. InitList(&L)
初始条件: 无
操作结果: 构造一个空的线性表 L。
2. DestroyList(&L)
初始条件: 线性表已经存在。
操作结果: 销毁线性表 L。
3. ListEmpty(L)
初始条件: 线性表已经存在。
操作结果: 若 L 为空表,则返回 TRUE,否则返回 FALSE。
4. ListLength(L)
初始条件: 线性表已经存在。
操作结果: 返回 L 中数据元素的个数。
5. SchoolReport(L, e)
初始条件: 线性表已经存在。
操作结果: 输出 L 中学校编号等于 e 的数据元素的(学校编号,项目编号,运动员姓名,比赛成绩),若这样的数据元素不存在则返回值为 0。
6. SchoolScore(L, e)
初始条件: 线性表已经存在。
操作结果: 输出 L 中学校编号等于 e 的数据元素的团体总分、女子团体总分、男子团体总分,若这样的数据元素不存在则返回值为 0。
7. AllSchoolScores(L)
初始条件: 线性表已经存在。
操作结果: 输出各个学校的团体总分、女子团体总分、男子团体总分。
8. Append(&L, e)
初始条件: 线性表已经存在。
操作结果: 在 L 的末尾插入一个元素 e。
数据结构定义
typedef struct record {
int event_num;
int competitor_rank;
string competitor_name;
int competitor_sch; // 学校编号
int competitor_score;
} state_record;
typedef struct {
state_record data[MAX_SIZE];
int size;
} List;
本程序包含三个主要模块:
主程序模块:负责初始化系统,接受用户命令,并根据命令调用相应的处理函数。
顺序表的单元模块:实现顺序表的抽象数据类型(ADT),提供对顺序表的基本操作。
结点结构的单元模块:定义顺序表的结点结构。
各模块之间的调用关系如下:
三、详细设计
1.结点结构的详细定义
typedef struct record{
int event_num;
int competitor_rank;
string competitor_name;
int competitor_score;
}state_record;
2.顺序表的详细定义及基本操作
state_record结构体用来存储每个参赛者的成绩记录,包含事件编号(event_num)、名次(competitor_rank)、姓名(competitor_name)和分数(competitor_score)。
使用二维数组 report_card 来保存所有学校的成绩记录,数组 p 用于追踪每个学校当前已经录入了多少条记录。
三个二维数组 boys_score, girls_score 和 total_score 分别用于存储每个学校男生、女生和总分的情况。其中,第一维索引代表学校编号,第二维的第一个元素是分数,第二个元素是学校编号。
3.主函数的算法
输入处理:
用户首先需要提供参赛学校的总数、男生项目数和女生项目数。
对于每个项目,用户需要指定项目类型(传统前五名计分赛、前三名计分赛或是自定义规则),并依次输入获得各名次的选手及其所在学校的信息。
评分机制:
根据选择的不同项目类型,程序使用相应的计分方式为每位参赛者打分,并更新相关学校的分数。如果选择了自定义规则,则还需要额外输入该规则下每一名次对应的分数值。
输出结果:
最终,程序将展示各个学校的男队分数、女队分数和总分,并且列出了每一位参与者的具体成绩。此外,还会根据总分对学校进行排名,并显示排名结果。
排序算法:
通过简单的冒泡排序方法对 boys_score, girls_score 和 total_score 进行降序排列,以便于最后打印出正确的排行榜。
4.函数的调用关系图
main() --> 初始化变量和数组 --> 获取用户输入数据 --> 处理每项赛事成绩 --> 输出学校成绩详情 --> 排序并输出排名
四、调试分析
1.算法的时空分析
由于采用顺序表,各种操作的算法时间复杂度基本合理。
时间复杂度分析
1. 初始化变量和数组:时间复杂度:O(n),其中 n 是学校数量。初始化过程中,对每个学校的分数、排名等进行设置。
2. 处理每项赛事成绩:对于每一个赛事(总共有 total_event_num 个赛事):如果是传统前5名计分或前3名计分,需要处理最多5或3个获奖者;如果是自定义计分,需要处理 new_rule_temp 个获奖者。时间复杂度:O(m * k),其中 m 是赛事总数,k 是每次赛事的最大获奖者数量(最大为5)。在最坏情况下,m = total_event_num,k = 5。
3. 输出学校成绩详情:遍历每个学校的记录并输出。时间复杂度:O(n * p),其中 n 是学校数量,p 是每个学校平均记录的数量。假设每个学校平均有 p 条记录。
4. 排序并输出排名:使用冒泡排序对所有学校的总分进行排序。时间复杂度:O(n^2),其中 n 是学校数量。冒泡排序的时间复杂度是 O(n^2)。(如果学校数量较多,可以考虑使用更高效的排序算法(如快速排序或归并排序)来优化性能)
总体时间复杂度 近似为 O(m * k + n^2)。
空间复杂度分析
1. 初始化变量和数组:空间复杂度:O(n + m * n * 6),其中 n 是学校数量,m 是赛事总数。report_card[school_num+1][6*total_event_num] 占用的空间是 O(m * n * 6)。
其他变量如 p, boys_score, girls_score, total_score 等占用的空间是 O(n)。
2. 获取用户输入数据
空间复杂度:O(1)。临时变量存储用户输入的数据。
3. 排序并输出排名
空间复杂度:O(1)。冒泡排序是原地排序算法。
总体空间复杂度 近似为O(m * n * 6)。
2.小结
实验使用顺序表实现,调试基本顺利,没有太大的修改,本人确实得到了一次很好的程序设计训练。然而,实验报告真的很难写。
五、用户手册
1、使用环境
操作系统:Windows, macOS, Linux
编译器:支持 C++11 或更高版本的标准编译器(如 GCC, Clang, MSVC)
输入设备:键盘
输出设备:显示器
2、使用说明
2.1 启动程序
运行程序后,首先会提示用户输入参赛学校的数量、男子项目的数量和女子项目的数量。
2.2 输入赛事信息
对于每一个赛事,程序会依次提示用户输入以下信息:
赛事编号:请输入当前赛事的唯一编号。
赛事类型:
输入 1 表示传统前5名计分比赛。
输入 2 表示传统前3名计分比赛。
输入 3 表示自定义计分比赛。
根据所选的赛事类型,输入获奖者的学校编号和姓名:
如果是传统前5名或前3名计分比赛,程序会要求输入前几名的获奖者信息。
如果是自定义计分比赛,程序会要求输入可以得分的名次数量以及每一名次的分数,然后输入相应名次的获奖者信息。
2.3 查看结果
当所有赛事的成绩都录入完毕后,程序会显示每个学校的详细得分情况,包括男队分数、女队分数和总分。
最后,程序会对所有学校的总分进行排序,并输出最终的排名。
六、测试结果
根据测试数据输入后,得到的结果如图:
七、附录
(附源代码,略)
第四部分 致谢
感谢各位读者的阅读。诚然本实验报告与实现代码还是十分不完善的,作为一次作业就不追求完美了,敬请谅解。
何年何夕 两相执手 蚀骨相思 风侵寒透 仙人近侧 怕倚小楼 金缕为笼 歌乐成囚
去思考,去尝试,去突破,去成长
衷心感谢您的阅读,我们下次再见!