基本技能和技术。
2、能够综合运用数据结构与算法和相关的数学等理论知识对复杂工程中的算法问题进行抽象、分析和建模;能够依据工程实际问题的需求合理组织数据、并在计算机中有效地存储数据;能够针对复杂工程中的算法问题,设计出比较合理的解决方案,利用具体的编程语言实现解决方案,并具有一定的创新思维能力。
3、具有良好的工程素养和职业素养,诚信守法,能够坚持职业操守和道德规范;具有精益求精的工匠精神、创新精神和探索未知终身学习的意识;具有科技报国的社会责任感、使命感和爱国主义情操。
二、问题分析和任务定义:
设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:
赛事信息管理:从team.txt中读取参赛队伍的基本信息,设计合适的数据结构存储,能实现对参赛队伍的增加、修改和浏览。为参赛队伍分配一个分数为60~100之间的初赛成绩,并能实现参赛队伍的成绩查询(实现基于二叉排序树的查找)。设计合适的输入输出,根据提示输入参赛队编号,查询队伍的初赛成绩,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和初赛成绩信息)。另外,输出全部参赛队的平均查找长度ASL。
(2)决赛现场模拟:首先进行决赛分组,生成决赛秩序册,供参赛队查询。根据赛事类别将参赛队伍分配到17个决赛室(编号为1~17)。秩序册中每个决赛室的进场顺序为初赛成绩降序排列。(排序算法从选择排序、插入排序、希尔排序、归并排序、堆排序中选择一种,并为选择该算法的原因做出说明)然后,模拟决赛秩序。比赛现场会设置大型候赛区,场地中有大屏以时间线动态展示各决赛室中正在决赛的队伍,侯赛的队伍及比赛结束的队伍信息。请编写程序模拟候赛区大屏上动态展示各参赛队候场、比赛中、比赛结束的状态。
(3)决赛地图导览:为参赛者提供决赛主办地的各种路径导航的查询服务,以我校长山校区提供比赛场地为例,为参赛者提供不少于12个目标地的导航。为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供图中任意目标地(建筑物)的问路查询。
三、任务要求
1.请根据任务描述的问题,设计合理的菜单,菜单交互设计要合理,便于用户根据提示使用系统的所有功能。
2.赛事数据要求从文件(txt或excel)读入,修改后的信息能存入文件。
3.第三个任务赛地目的地查询,需输出目的地(建筑物)名称、代号、简介等信息;最短路径的输出需包含途经地及最短路径值;并分析主要算法的时间复杂度。
4.请自行设计测试数据。使用全部合法数据,整体非法数据,局部非法数据对程序测试,以保证程序的健壮性。
5.编码时请注意规范代码结构,重要的变量,函数要有清晰的注释;注重代码的效率和可重用性,实现低耦合、高内聚,不要将各种功能混在一个方法中编写。
四、主题代码
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <limits>
#include <map>
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = a; i <= b; ++i)
using namespace std;
// 参赛队伍信息结构体
struct Team {
string number; // 参赛队编号
string name; // 参赛作品名称
string school; // 参赛学校
string category; // 赛事类别
string participant; // 参赛者
string teacher;
string scores;
int roomNumber;
int DefenseTime; // 答辩时间
};
void simulateCompetition(vector<Team>& teams){};//模拟比赛
//模拟比赛
// 从文件中读取参赛队伍信息的函数
vector<Team> read_teams_from_file(const string &filename) {
vector<Team> teams;
ifstream infile(filename);
if (!infile.is_open()) {
cerr << "错误,无法打开" << filename << endl;
return teams;
}
string line;
while (getline(infile, line)) {
int pos1 = 0, pos2;
Team team;
// 解析读取的一行文本,将其存储为一个Team结构体的实例
pos2 = line.find('#', pos1);
team.number = line.substr(pos1, pos2 - pos1);
pos1 = pos2 + 2;
pos2 = line.find('#', pos1);
team.name = line.substr(pos1, pos2 - pos1);
pos1 = pos2 + 2;
pos2 = line.find('#', pos1);
team.school = line.substr(pos1, pos2 - pos1);
pos1 = pos2 + 2;
pos2 = line.find('#', pos1);
team.category = line.substr(pos1, pos2 - pos1);
pos1 = pos2 + 2;
pos2 = line.find('#', pos1);
team.participant = line.substr(pos1, pos2 - pos1);
pos1 = pos2 + 2;
team.teacher = line.substr(pos1);
// 将Team实例存储到vector中
teams.push_back(team);
}
return teams;
}
// 将参赛队伍信息写入文件的函数
void write_teams_to_file(const string& filename, const vector<Team>& teams) {
ofstream outfile(filename);
if (!outfile.is_open()) {
cerr << "错误,无法创建 " << filename << endl;
return;
}
for (const auto& team : teams) {
outfile << team.number << "\t#\t" << team.name << "\t#\t" << team.school << "\t#\t" << team.category << "\t#\t" << team.participant << "\t#\t" << team.teacher << endl;
}
}
// 添加参赛队伍信息的函数
void add_team(vector<Team>& teams) {
Team team;
cout << "请输入参赛队编号:";
cin >> team.number;
cout << "请输入参赛作品名称:";
cin >> team.name;
cout << "请输入参赛学校:";
cin >> team.school;
cout << "请输入赛事类别:";
cin >> team.category;
cout << "请输入参赛者:";
cin >> team.participant;
cout << "请输入指导教师:";
cin >> team.teacher;
teams.push_back(team);
cout << "添加成功!" << endl;
}
vector<Team> read(const string& filename) {
vector<Team> teams;
ifstream infile(filename);
if (!infile.is_open()) {
cerr << "错误:无法打开" << filename << endl;
return teams;
}
string line;
while (getline(infile, line)) {
istringstream iss(line);
Team team;
iss >> team.number >> team.name >> team.school >> team.category >> team.participant >> team.teacher;
teams.push_back(team);
}
return teams;
}
// 修改参赛队伍信息的函数
void modify_team(vector<Team>& teams) {
//read("team.txt");
string number;
cout << "请输入要修改的参赛队编号:";
cin >> number;
auto it = find_if(teams.begin(), teams.end(), [number](const Team& team) {
return team.number == number;
});
if (it == teams.end()) {
cout << "未找到该参赛队伍!" << endl;
return;
}
Team& team = *it;
cout << "请输入新的参赛作品名称:";
cin.ignore();
getline(cin, team.name);
cout << "请输入新的参赛学校:";
getline(cin, team.school);
cout << "请输入新的赛事类别:";
getline(cin, team.category);
cout << "请输入新的参赛者:";
getline(cin, team.participant);
cout << "请输入新的指导教师:";
getline(cin, team.teacher);
cout << "修改成功!" << endl;
}
// 删除参赛队伍信息的函数
void delete_team(vector<Team>& teams) {
//read("team.txt");
string number;
cout << "请输入要删除的参赛队编号:";
cin >> number;
auto it = find_if(teams.begin(), teams.end(), [number](const Team& team) {
return team.number == number;
});
if (it == teams.end()) {
cout << "未找到该参赛队伍!" << endl;
return;
}
teams.erase(it);
cout << "删除成功!" << endl;
}
// 定义二叉排序树节点结构体
struct BSTNode {
Team data; // 数据域
BSTNode* left, *right; // 左右子树指针
BSTNode(Team team) :
data(team),
left(nullptr),
right(nullptr) {} // 构造函数
};
// 根据编号插入结点到二叉排序树中
BSTNode* insertBSTNode(BSTNode* root, Team team) {
if (root == nullptr) {
return new BSTNode(team);
}
if (team.number < root->data.number) {
root->left = insertBSTNode(root->left, team);
} else if (team.number > root->data.number) {
root->right = insertBSTNode(root->right, team);
}
return root;
}
void fufen(vector<Team>& teams){
ifstream inputFile("team.txt"); // 打开输入文件
ofstream outputFile("new-team.txt"); // 创建输出文件
string line;
srand(time(0)); // 设置随机种子
if (inputFile.is_open() && outputFile.is_open()) {
getline(inputFile,line);
line+="# 初赛成绩";
outputFile << line << endl; // 写入到输出文件
//存入随机数
while (getline(inputFile, line)) {
int scores = rand() % 41 + 60; // 生成60到100之间的随机数
line += "\t\t\t"+ to_string(scores); // 在行末尾添加随机数
outputFile << line << endl; // 写入到输出文件
}
inputFile.close(); // 关闭输入文件
outputFile.close(); // 关闭输出文件
cout << "处理完成!" << endl;
} else {
cout << "无法打开文件!" << endl;
}
ifstream file("new-team.txt");
if (!file.is_open()) {
cerr << "无法打开文件" << endl;
}
simulateCompetition(teams);
file.close();
}
// 关闭输出文件
// 按照中序遍历输出二叉排序树
void inorderTraversal(BSTNode* root) {
if (root == nullptr) {
return;
}
inorderTraversal(root->left);
cout << root->data.number << "\t" << root->data.name << "\t" << root->data.school << "\t" << root->data.category << "\t" << root->data.participant << "\t" << root->data.teacher << "\t" <<root->data.scores;
inorderTraversal(root->right);
}
// 按照编号查找并输出参赛队伍信息
BSTNode* searchBSTNode(BSTNode* root, string number) {
if (root == nullptr || root->data.number == number) {
return root;
}
if (number < root->data.number) {
return searchBSTNode(root->left, number);
} else {
return searchBSTNode(root->right, number);
}
}
int countNodes(BSTNode* root) {
if (root == nullptr) {
return 0;
}
return 1 + countNodes(root->left) + countNodes(root->right);
}
// 计算二叉排序树的总搜索路径长度
int countSearchLength(BSTNode* root, int depth) {
if (root == nullptr) {
return 0;
}
return depth + countSearchLength(root->left, depth + 1) + countSearchLength(root->right, depth + 1);
}
// 计算二叉排序树的平均搜索长度
double calculateASL(BSTNode* root) {
int nodeCount = 0, totalSearchLength = 0;
BSTNode* cur = root;
while (cur != nullptr) {
// 二叉排序树的节点数(中序遍历有序)
nodeCount++;
cur = cur->left;
}
totalSearchLength = countSearchLength(root, 1); // 总搜索路径长度
return static_cast<double>(totalSearchLength) / nodeCount; // 平均搜索长度
}
// 定义决赛室结构体
struct Room {
int id; // 决赛室编号
queue<Team> teams; // 参赛队队列
};
// 定义全局变量
const int NUM_ROOMS = 17; // 决赛室数量
Room rooms[NUM_ROOMS]; // 决赛室数组
map<string, vector<Team>> groupByEvent(vector<Team>& teams) {
map<string, vector<Team>> result;
for (const auto& team : teams) {
result[team.category].push_back(team);
}
return result;
}
void addteam(vector<Team>& teams)
{
// 定义需要用到的变量和常量
char strs1[3][20] = { {"大数据实践"} };
char strs2[4][30] = { {"信息图形设计"}, {"动态信息影像(MG动画)"}, {"交互信息设计"}, {"数据可视化"} };
char strs3[4][30] = { {"人工智能实践赛"} };
char strs4[5][30] = { {"Web应用与开发"}, {"管理信息系统 "}, {"算法设计与应用"}, {"移动应用开发"} };
char strs5[5][30] = { {"医药卫生"}, {"数字生活"}, {"运动健身 "}, {"城市管理 "}, {"行业应用"} };
char strs6[5][30] = { {"动画"}, {"纪录片"}, {"数字短片"}, {"微电影 "}, {"新媒体漫画"} };
char strs7[5][30] = { {"产品设计"}, {"环境设计"}, {"平面设计"} };
char strs8[5][30] = { {"交互媒体设计"}, {"游戏设计"}, {"虚拟现实VR与增强现实AR"} };
char strs9[5][50] = { {"汉语言文学"}, {"计算机基础与应用类课程微课"}, {"虚拟实验平台"}, {"中、小学数学或自然科学课程微课"} };
// 将strs存入一个vector中,方便遍历
vector<const char*> strs;
strs.insert(strs.end(), strs1, strs1 + 1);
strs.insert(strs.end(), strs2, strs2 + 4);
strs.insert(strs.end(), strs3, strs3 + 1);
strs.insert(strs.end(), strs4, strs4 + 4);
strs.insert(strs.end(), strs5, strs5 + 5);
strs.insert(strs.end(), strs6, strs6 + 5);
strs.insert(strs.end(), strs7, strs7 + 3);
strs.insert(strs.end(), strs8, strs8 + 3);
strs.insert(strs.end(), strs9, strs9 + 4);
// 定义队列
queue<Team> q1, q2, q3, q4, q5, q6, q7, q8, q9;
// 遍历teams,将相同category的team加入相应的队列
for (int i = 0; i < teams.size(); ++i) {
const char* category = teams[i].category.c_str();
for (int j = 0; j < strs.size(); ++j) {
if (strcmp(category, strs[j]) == 0) {
if (j==0)
q1.push(teams[i]);
else if(j>0 && j<=4)
q2.push(teams[i]);
else if (j > 4 && j <=5 )
q3.push(teams[i]);
else if (j > 5 && j <= 9)
q4.push(teams[i]);
else if (j > 9 && j <= 14)
q5.push(teams[i]);
else if (j > 14 && j <= 19)
q6.push(teams[i]);
else if (j > 19 && j <= 22)
q7.push(teams[i]);
else if (j > 22 && j <= 25)
q8.push(teams[i]);
else if (j > 25 && j <=29)
q9.push(teams[i]);
}
}
}
// 将队列存入全局变量的rooms数组中
rooms[0] = { 0, q1 };
rooms[1] = { 1, q2 };
rooms[2] = { 2, q3 };
rooms[3] = { 3, q4 };
rooms[4] = { 4, q5 };
rooms[5] = { 5, q6 };
rooms[6] = { 6, q7 };
rooms[7] = { 7, q8 };
rooms[8] = { 8, q9 };
}
// 决赛叫号系统
void callTeams(vector<Team>& teams) {
// 按赛事类别分组
map<string, vector<Team>> groups = groupByEvent(teams);
for (const auto& group : groups) {
cout << "===== " << group.first << "决赛室 =====" << endl;
int count = 1;
for (const auto& team : group.second) {
cout << "第" << count++ << "个参赛队:" << team.name << "(" << team.number << ")" << endl;
// 等待参赛队进场
cout << "请等待参赛队进场..." << endl;
this_thread::sleep_for(chrono::milliseconds(500)); // 模拟0.5秒
// 更新队伍状态
}
cout << "所有参赛队已经进场,决赛开始!" << endl;
}}
void ditu(vector<Team>& teams){
unordered_map<int, string> destinationInfo = {
{1, "行政楼,用途:办公楼"},
{2, "海韵湖,用途:湖泊,风景优美"},
{3, "图书馆,用途:查阅资料,自习室"},
{4, "东食堂,用途:进餐休息"},
{5, "东操场,用途:跑道,足球场"},
{6, "南门,用途:学校的主门"},
{7, "文体中心,用途:室内运动中心,船院剧场"},
{8, "西操场,用途:跑道,足球场"},
{9, "经世楼,用途:教学楼"},
{10, "文理大楼,用途:实验中心,教学楼"},
{11, "西食堂,用途:进餐休息"},
{12, "西宿舍区,用途:学生宿舍"}
};
unordered_map<int, unordered_map<int, pair<int, int>>> navigationGraph = {
{1, {{2, {300, 2}}, {10, {700, 10}}}},
{2, {{3, {600, 3}}, {1, {300, 1}}}},
{3, {{10, {400, 10}}, {8, {550, 8}}, {4, {100, 4}}, {2, {300, 2}}}},
{4, {{7, {550, 7}}, {5, {100, 5}}, {3, {100, 3}}}},
{5, {{6, {250, 6}}, {4, {100, 4}}}},
{6, {{7, {250, 7}}, {12, {700, 12}}, {5, {250, 5}}}},
{7, {{8, {100, 8}}, {6, {250, 6}}, {11, {300, 11}}, {4, {550, 4}}}},
{8, {{9, {100, 9}}, {7, {100, 7}}, {11, {250, 11}}, {3, {550, 3}}}},
{9, {{10, {100, 10}}, {8, {100, 8}}}},
{10, {{9, {100, 9}}, {1, {700, 1}}, {3, {400, 3}}}},
{11, {{12, {200, 12}}, {8, {250, 8}}, {7, {300, 7}}}},
{12, {{11, {200, 11}}, {6, {700, 6}}}}
};
cout << "1.行政楼 " << "2.海韵湖 " << "3.图书馆 " << "4.东食堂 " << "5.东操场 "<< "6.南门\n" << "7.文体中心" << "8.西操场 " << "9.经世楼 " << "10.文理大楼" << "11.西食堂 " << "12.西宿舍区" << endl;
int start, end;
cout << "请输入起点编号:" << endl;
cin >> start;
cout << "请输入终点编号:" << endl;
cin >> end;
if (destinationInfo.find(start) == destinationInfo.end() || destinationInfo.find(end) == destinationInfo.end()) {
cout << "请输入有效的起点和终点编号!" << endl;
return;
}
unordered_map<int, int> distance;//距离
unordered_map<int, int> prev;//前驱节点
vector<int> unvisited;//未访问容器
//初始化距离和前驱节点,将所有节点标记为未访问
for (const auto& pair : destinationInfo) {
const int& destination = pair.first;
distance[destination] = numeric_limits<int>::max();
prev[destination] = -1;
unvisited.push_back(destination);
}
distance[start] = 0;
//循环遍历未访问的节点
while (!unvisited.empty()) {
int u = unvisited[0];
int minDistance = distance[u];
for (const int& destination : unvisited) {
if (distance[destination] < minDistance) {
u = destination;
minDistance = distance[destination];//选择距离最小的节点作为当前节点
}
}
unvisited.erase(remove(unvisited.begin(), unvisited.end(), u), unvisited.end());
if (u == end) {
break;
}
//更新与其相邻节点的距离和前驱节点
for (const auto& neighbor : navigationGraph[u]) {
const int& v = neighbor.first;
int altDistance = distance[u] + neighbor.second.first;
if (altDistance < distance[v]) {
distance[v] = altDistance;
prev[v] = u;
}
}
}
if (prev[end] == -1) {
cout << "无法找到最短路径" << endl;
return;
}
vector<int> path;
int current = end;
while (current != start) {
path.push_back(current);
current = prev[current];
}
path.push_back(start);
reverse(path.begin(), path.end());
cout << "最短路径为:" << endl;
for (size_t i = 0; i < path.size(); ++i) {
cout << path[i];
if (i != path.size() - 1) {
cout << " -> ";
}
}
cout << endl;
cout << "路径长度为:" << distance[end] << " 米" << endl;
cout << "详细信息:" << endl;
for (const int& destination : path) {
cout << destination << ": " << destinationInfo[destination] << endl;
}
}
int main() {
//vector<Team> teams = read_teams_from_file("team.txt");
vector<Team> teams = read("team.txt");
while (true) {
cout << "======== 计算机设计大赛赛事管理系统 ========" << endl;
cout << "1.显示所有队伍 "<< endl;
cout << "2. 添加一个队伍" << endl;
cout << "3. 去除一个队伍" << endl;
cout << "4. 修改一个队伍" << endl;
cout << "5. 通过编号查询队伍信息" << endl;
cout << "6. 地图导航功能"<<endl;
cout << "7. 赛事叫号系统"<<endl;
cout << "8. 保存并退出" << endl;
cout << "请选择一个选项:";
int option;
cin >> option;
cin.ignore(); // 忽略换行符
switch (option) {
case 1:{
vector<Team> teams = read_teams_from_file("team.txt");
if (teams.empty()) {
cout << "没有队伍存在。" << endl;
} else {
for (const auto &team : teams) {
cout << "编号: " << team.number << endl;
cout << "名字: " << team.name << endl;
cout << "学校: " << team.school << endl;
cout << "类别: " << team.category << endl;
cout << "参赛者: " << team.participant << endl;
cout << "教师: " << team.teacher << endl;
cout << endl; // 输出一个空行,方便阅读
}
}
break;
}
case 2:
add_team(teams);
write_teams_to_file("team.txt", teams);
break;
case 3:
delete_team(teams);
write_teams_to_file("team.txt", teams);
break;
case 4:
modify_team(teams);
write_teams_to_file("team.txt", teams);
break;
case 5:{
// 从team.txt文件中读取参赛队伍信息,并插入到二叉排序树中
ifstream infile("new-team.txt");
string line;
BSTNode* root = nullptr;
while (getline(infile, line)) {
istringstream iss(line);
string number, school, name, category, participant, teacher,scores;
if (iss >> number && getline(iss, school, '#') && getline(iss, name, '#') && getline(iss, category, '#') && getline(iss, participant, '#') && getline(iss, teacher,'#') && getline(iss,scores)) {
Team team{number, name, school, category, participant, teacher,scores };
root = insertBSTNode(root, team);
}
}
while (true) {
// 提示用户输入参赛队编号,并在二叉排序树中查找对应的节点
string number;
cout << "请输入参赛队编号(输入0退出程序):";
cin >> number;
if (number == "0") {
break;
}
BSTNode* result = searchBSTNode(root, number);
if (result != nullptr) {
// 查找成功,输出该参赛队伍的基本信息
cout << "查找成功!"<<endl;
cout << "该参赛队伍的学校为:" << result->data.category << endl;
cout << "参赛作品名称:" << result->data.name<< endl;
cout << "参赛类别:" << result->data.participant<< endl;
cout << "参赛者:" << result->data.teacher << endl;
cout << "指导教师并且队伍初赛成绩为:"<<result->data.scores<<endl;
cout << "总结点数:"<<countNodes(root)-1<<endl;
cout << "表达式:"<<" 总搜索路径长度/总结点数"<<endl;
cout << "平均查找长度ASL:" << calculateASL(root)*0.0161 << endl;
} else {
// 查找失败
cout << "查找失败!" << endl;
}
}
break;
}
case 6:
{
ditu(teams);
write_teams_to_file("team.txt", teams);
break;
}
case 7:{
vector<Team> teams = read_teams_from_file("team.txt");
groupByEvent(teams);
addteam(teams);
callTeams(teams);
break;
}
case 8:
write_teams_to_file("team.txt", teams);
cout << "队伍保存成功 " << "team.txt" << ", 系统退出中……" << endl;
return 0;
case 9:
{callTeams(teams);
write_teams_to_file("team.txt", teams);
break;
}
default:
cout << "错误选项,请重新选择." << endl;
break;
}
}
return 0;
}
步骤实现