中国大学生计算机设计大赛

一:具体内容

中国大学生计算机设计大赛是我国高校面向本科生的计算机应用设计大赛,大赛旨在激发学生学习计算机知识和技能的兴趣与潜能,提高学生运用信息技术解决实际问题的综合能力。通过大赛这种计算机教学实践形式,可展示师生的教与学成果,最终以赛促学,以赛促教,以赛促创。该赛事在历届学生中影响力较大,参与者众多,请结合2021届省赛参赛的数据,借助数据结构课程所学的相关知识,通过对数据的处理和分析,熟悉数据结构设计及数据处理在信息管理系统中应用的重要性。赛事相关数据存储在文本文件和excel文件中,相应的文件信息说明如表1所示。其中,各个文件中不同的数据项之间均使用#分隔,图1中给出了文件team.txt中参赛信息的对应数据示例。

                      

图1.参赛队基本信息

二:问题描述 

本次课程设计要求协助中国大学生计算机设计大赛江苏省组委会,设计一款赛事管理系统,实现赛务相关的数据管理及信息服务,该系统能够为省级赛事管理解决以下问题:

(1)能够管理各参赛队的基本信息(包含参赛队编号,参赛作品名称,参赛学校,赛事类别,参赛者,指导老师),赛事类别共11项(参见大赛官网jsjds.blcu.edu.cn);包括增加、删除、修改参赛队伍的信息。

(2)从team.txt中读取参赛队伍的基本信息,实现基于二叉排序树的查找。根据提示输入参赛队编号,若查找成功,输出该赛事类别对应的基本信息(参赛作品名称、参赛学校、赛事类别、参赛者和指导老师信息),同时,输出查找成功时的平均查找长度ASL;否则,输出“查找失败!”。
(3)能够提供按参赛学校查询参赛团队(或根据赛事类别查询参赛团队),即,根据提示输入参赛学校名称(赛事类别),若查找成功,输出该学校参赛的(该赛事类别的)所有团队的基本信息,输出的参赛团队按赛事类别有序输出。(排序算法可从选择排序、插入排序、希尔排序、归并排序、堆排序中任意选择,并为选择算法的原因做出说明。)

(4)为省赛现场设计一个决赛叫号系统。所有参赛队按赛事组织文件中的赛事类别分到9个决赛室,决赛室按顺序叫号,被叫号参赛队进场,比赛结束后,下一参赛队才能进赛场。请模拟决赛叫号系统,演示省赛现场各决赛室的参赛队进场情况。(模拟时,要能直观展示叫号顺序与进场秩序一致)

(5)赛事系统为参赛者提供赛地的校园导游程序,为参赛者提供各种路径导航的查询服务。以我校长山校区提供比赛场地为例,(请为参赛者提供不少于10个目标地的导航。可为参赛者提供校园地图中任意目标地(建筑物)相关信息的查询;提供任意两个目标地(建筑物)的导航查询,即查询任意两个目的地(建筑物)之间的一条最短路径。

三:相关代码

3.1管理参赛队的基本信息

/ 构造函数
    Team(int number, const std::string& name, const std::string& sch, EventCategory category, const std::vector<std::string>& part, const std::string& t) :
        teamNumber(number), projectName(name), school(sch), eventCategory(category), participants(part), teacher(t) {}

    // 获取参赛队编号
    int getTeamNumber() const {
        return teamNumber;
    }

    // 获取参赛队作品名称
    std::string getProjectName() const {
        return projectName;
    }

    // 获取参赛队学校
    std::string getSchool() const {
        return school;
    }

    // 获取赛事类别
    EventCategory getEventCategory() const {
        return eventCategory;
    }

    // 获取参赛者
    std::vector<std::string> getParticipants() const {
        return participants;
    }

    // 获取指导老师
    std::string getTeacher() const {
        return teacher;
    }

    // 修改参赛队信息
    void updateTeamInfo(const std::string& name, const std::string& sch, EventCategory category, const std::vector<std::string>& part, const std::string& t) {
        projectName = name;
        school = sch;
        eventCategory = category;
        participants = part;
        teacher = t;
    }
};

上述代码定义了一个名为Team的类,该类表示参赛团队的信息。以下是对代码的解析:

构造函数:
构造函数接受参赛队的编号 number、作品名称 name、学校名称 sch、赛事类别 category、参赛者列表 part 和指导老师姓名 t。
构造函数使用参数初始化列表来初始化类的成员变量。
成员函数:
getTeamNumber(): 返回参赛队的编号。
getProjectName(): 返回参赛队的作品名称。
getSchool(): 返回参赛队所属的学校名称。
getEventCategory(): 返回参赛队的赛事类别。
getParticipants(): 返回参赛队的参赛者列表。
getTeacher(): 返回参赛队的指导老师姓名。
updateTeamInfo(): 修改参赛队的信息。接受参数 name、sch、category、part 和 t,用于更新参赛队的作品名称、学校、赛事类别、参赛者列表和指导老师。
这段代码定义了一个简单的类来表示参赛团队的信息,并提供了获取和更新参赛队信息的方法。使用这个类,你可以创建参赛团队对象,并通过调用成员函数来获取和修改参赛团队的各个属性。例如,你可以使用 getTeamNumber() 方法来获取参赛队的编号,使用 getProjectName() 方法来获取参赛队的作品名称。

3.2二叉排序树的查找

// 递归实现二叉排序树的查找
    TreeNode* searchNode(TreeNode* node, int teamNumber, int& ASL) {
        if (node == nullptr || node->team.getTeamNumber() == teamNumber) {
            return node;
        }

        ASL++;
        if (teamNumber < node->team.getTeamNumber()) {
            return searchNode(node->left, teamNumber, ASL);
        }
        else {
            return searchNode(node->right, teamNumber, ASL);
        }
    }

    // 查找节点
    TreeNode* searchNode(int teamNumber, double& ASL) {
        int pathLength = 0;
        TreeNode* node = searchNode(root, teamNumber, pathLength);
        ASL = static_cast<double>(pathLength) / countNodes;  // 计算平均查找长度
        return node;
    }
};

searchNode(TreeNode* node, int teamNumber, int& ASL): 这个私有的递归函数用于在二叉排序树中查找给定 teamNumber 的节点。它接受一个当前节点 node、要查找的 teamNumber 和一个引用 ASL 作为参数。ASL 是一个计数器,用于计算平均查找长度(Average Search Length)。
首先检查当前节点 node 是否为 nullptr,如果是则返回 nullptr,表示未找到对应的节点。
如果当前节点的 teamNumber 等于要查找的 teamNumber,则返回当前节点。
否则,将 ASL 加一,表示经过了一次查找操作。
如果要查找的 teamNumber 小于当前节点的 teamNumber,则递归调用 searchNode 函数,在左子树中继续查找。
如果要查找的 teamNumber 大于当前节点的 teamNumber,则递归调用 searchNode 函数,在右子树中继续查找。
searchNode(int teamNumber, double& ASL): 这个公有的函数是对外的接口,用于查找给定 teamNumber 的节点,并返回该节点。它接受一个 teamNumber 和一个引用 ASL 作为参数,用于返回平均查找长度。
创建一个变量 pathLength,用于记录查找路径的长度。
调用私有的递归函数 searchNode,并将根节点 root、要查找的 teamNumber 和 pathLength 传递给它。
计算平均查找长度 ASL,即 pathLength 除以总节点数 countNodes。
返回查找到的节点。
这段代码使用递归的方式在二叉排序树中查找指定的节点。它根据给定的 teamNumber 与当前节点的 teamNumber 的大小关系,递归地在左子树或右子树中进行查找,直到找到匹配的节点或遍历到叶子节点为止。在查找的过程中,通过累加 ASL 计数器,记录查找的路径长度。最终返回查找到的节点,并计算平均查找长度。

3.3根据参赛学校查询参赛团队

void searchTeamsBySchool(const vector<Team>& teamList, const string& schoolName) {
    vector<Team> result;

    for (const auto& team : teamList) {
        if (team.school == schoolName) {
            result.push_back(team);
        }
    }

    if (!result.empty()) {
        sort(result.begin(), result.end(), [](const Team& a, const Team& b) {
            return a.category < b.category;
            });

        cout << "参赛学校:" << schoolName << endl;
        cout << "参赛团队信息:" << endl;

        for (const auto& team : result) {
            cout << "参赛队编号:" << team.number << endl;
            cout << "参赛作品名称:" << team.projectName << endl;
            cout << "赛事类别:" << team.category << endl;
            cout << "参赛者:" << team.participants << endl;
            cout << "指导教师:" << team.teacher << endl;
            cout << endl;
        }
    }
    else {
        cout << "未找到指定学校的参赛队伍信息!" << endl;
    }
}

这段代码实现了按参赛学校查询参赛团队的功能。

  • searchTeamsBySchool(const vector<Team>& teamList, const string& schoolName): 这个函数接受一个参赛团队列表 teamList 和一个学校名称 schoolName,用于查找指定学校的参赛团队。
    • 创建一个空的 result 向量,用于存储匹配学校的参赛团队。
    • 使用范围-based for 循环遍历 teamList 中的每个参赛团队。
    • 如果参赛团队的 school 成员变量与指定的学校名称相等,将该团队添加到 result 向量中。
    • 如果 result 向量不为空,表示找到了匹配的参赛团队,进行以下操作:
      • 使用 sort 函数对 result 向量进行排序,排序的依据是团队的赛事类别,以升序方式进行排序。
      • 输出参赛学校的名称 schoolName
      • 输出参赛团队的信息,包括团队编号、作品名称、赛事类别、参赛者列表和指导教师。
    • 如果 result 向量为空,表示未找到指定学校的参赛团队,输出相应的提示信息。

这段代码通过遍历参赛团队列表,将匹配指定学校的团队收集到 result 向量中,然后对 result 向量按照赛事类别进行排序,最后输出排序后的参赛团队的信息。

3.4决赛叫号系统

void callTeams(vector<Team>& teamList) {
    // 按照参赛队伍编号排序
    sort(teamList.begin(), teamList.end(), compareByNumber);

    // 创建决赛室队列
    queue<int> finalRooms;
    for (int i = 1; i <= 9; i++) {
        finalRooms.push(i);
    }

    cout << "决赛叫号系统:" << endl;

    // 依次叫号并进场
    for (auto& team : teamList) {
        if (!finalRooms.empty()) {
            int roomNumber = finalRooms.front();
            finalRooms.pop();

            cout << "参赛队编号:" << team.number << ",参赛作品名称:" << team.projectName << ",前往决赛室:" << roomNumber << endl;

            // 模拟比赛进行
            cout << "比赛开始,参赛队编号:" << team.number << ",参赛作品名称:" << team.projectName << ",参赛学校:" << team.school << endl;

            // 模拟比赛进行,延时2秒
            cout << "比赛进行中..." << endl;
            this_thread::sleep_for(chrono::seconds(2));

            // 比赛结束,离开决赛室,释放决赛室号码
            cout << "比赛结束,参赛队编号:" << team.number << ",参赛作品名称:" << team.projectName << ",参赛学校:" << team.school << ",离开决赛室:" << roomNumber << endl;
            finalRooms.push(roomNumber);

            cout << "比赛结束,参赛队编号:" << team.number << ",离开决赛室:" << roomNumber << endl;

            // 比赛结束,离开决赛室,释放决赛室号码
            finalRooms.push(roomNumber);
        }
        else {
            cout << "无可用决赛室,参赛队编号:" << team.number << ",暂时无法进入比赛。" << endl;
        }
    }

    cout << "决赛叫号系统结束。" << endl;

上述代码是一个模拟决赛叫号系统的函数`callTeams`的实现。函数接受一个存储参赛队伍信息的向量`teamList`作为参数。

1. 首先,使用`sort`函数对`teamList`中的参赛队伍按照队伍编号进行排序,排序依据由`compareByNumber`函数提供。

2. 创建一个队列`finalRooms`来表示决赛室的可用编号。决赛室的编号从1到9。

3. 输出提示信息`"决赛叫号系统:"`

4. 遍历`teamList`中的每个参赛队伍:

   a. 如果还有可用的决赛室(`finalRooms`队列非空):
   
      - 获取当前可用的决赛室编号,并从队列中移除。
      
      - 输出当前参赛队伍的编号、参赛作品名称和决赛室编号,提示队伍前往决赛室。
      
      - 模拟比赛进行,输出参赛队伍的编号、参赛作品名称和参赛学校。
      
      - 模拟比赛进行2秒钟(使用`this_thread::sleep_for`函数进行延时)。
      
      - 输出比赛结束的提示信息,包括参赛队伍的编号、参赛作品名称、参赛学校和离开的决赛室编号。
      
      - 将离开的决赛室编号放回`finalRooms`队列,以便后续队伍使用。
      
      - 输出比赛结束的提示信息,包括参赛队伍的编号和离开的决赛室编号。
      
      - 将离开的决赛室编号放回`finalRooms`队列,以便后续队伍使用。
      
   b. 如果没有可用的决赛室(`finalRooms`队列为空):
   
      - 输出无可用决赛室的提示信息,包括参赛队伍的编号,表示该队伍暂时无法进入比赛。
      
5. 输出提示信息`"决赛叫号系统结束。"`

3.5校园导游程序

void setDistance(int from, int to, int distance) {
        distances[from][to] = distance;
        distances[to][from] = distance;
    }

    int findBuildingIndex(const string& name) {
        for (int i = 0; i < buildings.size(); ++i) {
            if (buildings[i].name == name) {
                return i;
            }
        }
        return -1;
    }

    vector<int> findShortestPath(const string& start, const string& end) {
        int startIdx = findBuildingIndex(start);
        int endIdx = findBuildingIndex(end);

        if (startIdx == -1 || endIdx == -1) {
            return {};
        }

        int numBuildings = buildings.size();
        vector<int> distance(numBuildings, numeric_limits<int>::max());
        vector<bool> visited(numBuildings, false);
        vector<int> parent(numBuildings, -1);

        distance[startIdx] = 0;

        for (int i = 0; i < numBuildings - 1; ++i) {
            int minDist = numeric_limits<int>::max();
            int minIdx = -1;

            for (int j = 0; j < numBuildings; ++j) {
                if (!visited[j] && distance[j] < minDist) {
                    minDist = distance[j];
                    minIdx = j;
                }
            }

            if (minIdx == -1) {
                break;
            }

            visited[minIdx] = true;

            for (int j = 0; j < numBuildings; ++j) {
                if (!visited[j] && distances[minIdx][j] != numeric_limits<int>::max()
                    && distance[minIdx] + distances[minIdx][j] < distance[j]) {
                    distance[j] = distance[minIdx] + distances[minIdx][j];
                    parent[j] = minIdx;
                }
            }
        }

        vector<int> path;
        int curr = endIdx;
        while (curr != -1) {
            path.push_back(curr);
            curr = parent[curr];
        }

        reverse(path.begin(), path.end());
        return path;
    }
};


`setDistance` 函数用于设置建筑物之间的距离。它接受三个参数:起始建筑物的索引 `from`,目标建筑物的索引 `to`,以及它们之间的距离 `distance`。该函数会在距离矩阵 `distances` 中更新 `from` 和 `to` 之间的距离,因为这是一个无向图,所以同时也会更新 `to` 和 `from` 之间的距离。

`findBuildingIndex` 函数用于根据建筑物的名称查找其在建筑物列表中的索引。它接受一个参数 `name`,表示要查找的建筑物名称。函数会遍历建筑物列表,如果找到与 `name` 匹配的建筑物名称,则返回该建筑物的索引。如果未找到匹配的建筑物,则返回 -1。

`findShortestPath` 函数用于查找两个建筑物之间的最短路径。它接受两个参数 `start` 和 `end`,分别表示起始建筑物和目标建筑物的名称。函数首先使用 `findBuildingIndex` 函数找到起始建筑物和目标建筑物在建筑物列表中的索引,然后使用 Dijkstra 算法来计算最短路径。

函数内部首先检查起始建筑物和目标建筑物的索引是否有效,如果无效则返回一个空的路径。接下来,函数会初始化一些辅助数据结构,包括一个存储每个建筑物到起始建筑物的距离的数组 `distance`,一个标记建筑物是否已访问的数组 `visited`,以及一个存储最短路径上每个建筑物的父节点索引的数组 `parent`。

然后,函数会进行迭代,每次选择一个未访问的建筑物中距离起始建筑物最近的建筑物,然后更新其他未访问建筑物到起始建筑物的距离。这个过程会持续进行,直到所有建筑物都被访问或无法继续更新距离。

最后,函数会构建最短路径,从目标建筑物开始,沿着父节点索引逆序遍历,将每个建筑物的索引添加到路径中。然后,路径会被反转,以使起始建筑物在路径的开头,最终返回这个最短路径。

这部分代码提供了计算最短路径的功能,可以帮助参赛者查询任意两个建筑物之间的最短路径,并返回作为

导航结果。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容提要 2017年(第10届)中国大学生计算机设计大赛(以下简称“大赛”或“国赛”)是由中国高等教育学会、教育部高等学校计算机类专业教学指导委员会、软件工程专业教学指导委员会、大学计算机课程教学指导委员会、文科计算机基础教学指导分委员会联合组成的中国大学生计算机设计大赛组织委员会主办的面向全国高校在校本科学生的非盈利、公益性、科技型的群众性活动。 大赛的目的在于落实高等学校创新能力提升计划,进一步推动本科学生计算机教学改革,激发学生学习计算机知识和技能的兴趣和潜能,提高其运用信息技术解决实际问题(为就业及专业服务所需要)的综合能力,以培养德智体美全面发展、具有团队合作意识、创新创业能力的综合型、应用型的人才。大赛将本着公开、公平、公正的原则面对每一件作品。 为了更好地指导2017年的大赛大赛组委会组编了《中国大学生计算机设计大赛2017年参赛指南》。 《参赛指南》共分11章。由第1章大赛通知,第2章大赛章程,第3章大赛组委会,第4章大赛内容及分类,第5章国赛与地方赛,第6章国赛现场决赛的申办、时间地点与内容,第7章参赛事项,第8章奖项设置,第9章作品评比与评比专家规范,第10章获奖作品的研讨,以及第11章2016年获奖概况与2016年获奖作品选登等组成。 本书有助于规范参赛作品和提高大赛作品质量。因此是参赛院校,特别是参赛队指导教师的必备用书,也是参赛学生的重要参考资料。此外,也是从事计算机技术基本应用教学与多媒体设计教学很好的参考用书。而对于2016年已参赛一、二等获奖的师生,则具有一定的收藏价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值