World Robot Contest2025-2026Algorithm Application ThemeJunior Highwrc.hao.work
WRC
Contest Archive / Structured Dossiers青少年算法应用训练档案馆

把训练题、知识点、执行证据和最终解题档案统一归档成可直接浏览的竞赛资料库。

Archive30 Cases

四大文化赛道完整展开

AccessHTTPS

完整题面 / 题解 / 运行证据

No Rounded CornersTailwind FirstDossier Ready
Scene 03 / 丝路文化 / s3-jh-05-station-relay

丝路驿站传信:最少换站次数与最短耗时路径

在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。

优化求解初中组算法初步编程实践跨学科应用
Archive Brief

当前页面按竞赛 dossier 结构收纳题目总览、题面、题解、代码附录、运行附录和最终报告。 单题资料已经准备成可跳读的入口板,不需要来回切多个目录确认内容是否齐全。

Overview

题目总览与案例说明

43 text files

这里先给出题目的完整总览,便于在进入正式题面与题解前先建立背景、任务边界和知识点映射。

在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。

训练题定位

  • case_id: s3-jh-05-station-relay
  • scene: 丝路文化赛道
  • language_scope: python,cpp
  • judge_mode: optimization
  • rulebook_pages: 12-13

题目任务

丝路传信任务需要从起点驿站把信息送到终点驿站。路线选择时先看换站次数是否最少,若换站次数相同,再比较总耗时。为了便于调度,还要恢复满足双关键字最优的完整路径。

  • 读取驿站图并建立无向邻接表。
  • 先最小化经过的道路条数,也就是换站次数。
  • 在换站次数最少的前提下,再最小化总耗时,并输出完整路径。

完整知识点清单

  • 邻接表建图。
  • 双关键字状态比较 (steps, days)
  • 优先队列维护最优状态。
  • 前驱数组恢复完整路径。
  • 不可达结果输出。

输入输出总览

输入

  1. 第一行输入 n m s t,表示驿站数、道路数、起点和终点。
  2. 接下来 m 行每行输入 u v days,表示一条无向道路及所需天数。

输出

  1. 可达时第一行输出 relay_count=最少换站次数
  2. 第二行输出 total_days=对应总天数
  3. 第三行输出 path= 后接 a->b->c 形式路径。
  4. 不可达时依次输出 relay_count=-1total_days=-1path=IMPOSSIBLE

推荐解法总览

  • 主算法:双关键字最短路 + 路径恢复
  • 主流程:先完成输入建模,再按照题目要求逐步计算,最后统一整理输出。
  • 重点边界:终点不可达时必须按固定三行格式输出。

样例

输入

5 6 1 5
1 2 2
2 5 3
1 3 1
3 4 1
4 5 1
2 3 1

输出

relay_count=2
total_days=5
path=1->2->5

关联知识条目

  • ../../30-knowledge-base/02-algorithm-basics/graph-search-and-path-recovery.md
  • ../../30-knowledge-base/04-interdisciplinary-applications/modeling-patterns.md
  • ../../30-knowledge-base/05-cultural-contexts/silk-road-culture.md

目录说明

  • 01-requirements/:正式题面、约束、评分和验收清单
  • 02-solution/:样例、Python / C++ 主实现与解题说明
  • 03-execution/:运行证据、日志和输出快照
  • 04-debug/:调试日志、失败案例目录、编码过程记录
  • 05-rationale/:建模说明、方案选择、验证计划和备选方案
  • 06-deliverables/:完整解题档案、最终报告、代码附录、运行附录
  • official_overlay/:题面接入说明
Curated Dossier

单独整理的题目与解题档案

6 entries

下列入口把题目、题干、题解、最终代码、运行结果和全过程按交付视角重新整理,适合单独阅读、导出和联动复盘。

Full Inline Dossier

完整解题档案正文

打开独立文件页

当前案例的题目、题干、知识点、题解、代码、运行结果和流程留痕已经在这里整页展开,不需要再跳转多个文件分别查找。

档案概况

项目内容
Case IDs3-jh-05-station-relay
文化赛道Scene 03 / 丝路文化
组别初中组
判题方式优化求解
语言范围python,cpp
赛项页码12-13
仓库总览s3-jh-05-station-relay/README.md

题目、题干与输入输出

正式题面

源文件:official-prompt.md

规则来源

  • 赛项说明页码:12-13
  • 训练题主题:丝路驿站传信:最少换站次数与最短耗时路径
  • 所属赛道:丝路文化赛道

题目背景

丝路传信任务需要从起点驿站把信息送到终点驿站。路线选择时先看换站次数是否最少,若换站次数相同,再比较总耗时。为了便于调度,还要恢复满足双关键字最优的完整路径。

任务描述

  • 读取驿站图并建立无向邻接表。
  • 先最小化经过的道路条数,也就是换站次数。
  • 在换站次数最少的前提下,再最小化总耗时,并输出完整路径。

输入格式

  1. 第一行输入 n m s t,表示驿站数、道路数、起点和终点。
  2. 接下来 m 行每行输入 u v days,表示一条无向道路及所需天数。

输出格式

  1. 可达时第一行输出 relay_count=最少换站次数
  2. 第二行输出 total_days=对应总天数
  3. 第三行输出 path= 后接 a->b->c 形式路径。
  4. 不可达时依次输出 relay_count=-1total_days=-1path=IMPOSSIBLE

数据范围与说明

  • 2 <= n <= 200。
  • 1 <= m <= 1000。
  • 1 <= days <= 50。
  • 答案保证按“换站次数最少,再总天数最少”后唯一。

样例输入

5 6 1 5
1 2 2
2 5 3
1 3 1
3 4 1
4 5 1
2 3 1

样例输出

relay_count=2
total_days=5
path=1->2->5

样例解释

  • 路径 1->2->5 只经过两条道路,因此换站次数为 2
  • 另一条 1->3->4->5 虽然总天数更短,但换站次数为 3,不满足主关键字最优。
  • 因此最终答案是 relay_count=2total_days=5

知识点清单

  • 邻接表建图。
  • 双关键字状态比较 (steps, days)
  • 优先队列维护最优状态。
  • 前驱数组恢复完整路径。
  • 不可达结果输出。

约束拆解

源文件:parsed-constraints.md

显式约束

  • 2 <= n <= 200。
  • 1 <= m <= 1000。
  • 1 <= days <= 50。
  • 答案保证按“换站次数最少,再总天数最少”后唯一。

建模拆解

  • 先明确输入的实体和字段,再把它们翻译成 双关键字最短路 + 路径恢复 需要的数据结构。
  • 把输出中每一项指标都和中间变量对应起来,避免最后临时拼装。
  • 先用样例手推一次,再确认边界条件是否都能走到正确分支。

易错边界

  • 终点不可达时必须按固定三行格式输出。
  • 同一节点可能被不同天数和不同换站次数重复到达,必须按二元组比较。
  • 路径恢复时要注意起点前驱的终止标记。

计分模型

源文件:scoring-model.md

判题方式

  • 主判题方式:optimization
  • 主算法:双关键字最短路 + 路径恢复

判题重点

  • 重点校验建模是否正确、最优值维护是否稳定、路径或方案恢复是否完整。
  • 隐藏数据会覆盖不可达、同值竞争和多约束并存情形。

公开样例建议

  • 至少准备 1 组题面样例、2 组边界样例和 2 组自定义回归样例。
  • 多输出题必须验证所有字段都来自同一套方案。

隐藏数据建议

  • 准备多条路径换站次数不同的样例,验证主关键字优先级。
  • 准备换站次数相同但总天数不同的样例,验证次关键字比较。
  • 准备不可达图和单边直连图两类极端情况。

验收清单

源文件:acceptance-checklist.md

  • 正式题面、约束拆解、评分说明均已补齐
  • 样例输入输出已定义并通过主实现校验
  • python 主实现已提供并与样例输出对齐
  • cpp 主实现已提供并与样例输出对齐
  • 调试记录、决策记录、验证计划已补齐
  • 可由 20-tools/assemble_case_dossiers.py 汇总为完整解题档案

样例输入输出

样例输入:sample.in

5 6 1 5
1 2 2
2 5 3
1 3 1
3 4 1
4 5 1
2 3 1

样例输出:sample.out

relay_count=2
total_days=5
path=1->2->5

题解、建模与最终解法

自动整理的解题流程

  • 题目主题:丝路驿站传信:最少换站次数与最短耗时路径
  • 题目摘要:在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。
  • 判题提示:该题以优化求解为主,重点是约束建模、可行性检查和最优值维护。
  • 先完成输入、对象、约束和输出的四步建模,再落到具体算法和实现。
  • 优先用样例验证最小流程,再补边界测试和错误分支。

解题思路

源文件:solution-rationale.md

1. 问题重述

在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。

2. 数据结构与建模

  • 主算法:双关键字最短路 + 路径恢复
  • 输入拆解后对应的数据结构要和输出项一一对应。
  • 需要重点维护的状态包括:题目实体、核心指标、中间结果和最终答案。

3. 算法步骤

  1. 把每个节点的最优状态定义为 (换站次数, 总天数) 二元组。
  2. 用优先队列按字典序扩展当前最优状态。
  3. 若新状态字典序更小,就更新目标节点并记录前驱。
  4. 搜索结束后根据前驱数组恢复最优路径。

4. 正确性说明

  • 每一步都严格对应题面给出的规则或约束。
  • 所有输出字段都来自同一份计算过程,不会出现“各算各的”的不一致情况。
  • 边界情况通过单独分支或统一规则处理,保证程序在最小规模和重复值情况下也稳定。

5. 复杂度分析

  • 复杂度取决于输入规模和主算法,但整体设计保持在初中组可讲解、可验证的范围内。
  • 只保留必要状态,不引入超出题意的数据结构。

6. 易错点

  • 终点不可达时必须按固定三行格式输出。
  • 同一节点可能被不同天数和不同换站次数重复到达,必须按二元组比较。
  • 路径恢复时要注意起点前驱的终止标记。

7. 知识点清单

  • 邻接表建图。
  • 双关键字状态比较 (steps, days)
  • 优先队列维护最优状态。
  • 前驱数组恢复完整路径。
  • 不可达结果输出。

设计决策记录

源文件:decision-log.md

  • 选择 双关键字最短路 + 路径恢复 作为主算法,因为它能直接覆盖题目的核心约束。
  • 本题不能只看总天数,必须把换站次数放在首要比较位置。
  • 二元组最短路模型比枚举所有路径更稳定且易于恢复答案。
  • Python 与 C++ 版本统一输出格式,便于双语训练和证据采集。

验证计划

源文件:validation-plan.md

  • 先验证题面公开样例,确保基础流程无误。
  • 准备多条路径换站次数不同的样例,验证主关键字优先级。
  • 准备换站次数相同但总天数不同的样例,验证次关键字比较。
  • 准备不可达图和单边直连图两类极端情况。
  • 最后再补 1 组手工构造的极小数据,确认程序不会依赖特殊输入规模。

备选方案

源文件:alternatives.md

方案时间复杂度 / 代价实现难度说明
枚举所有简单路径指数级节点不大但路径数太多,不可取。
双关键字优先队列主方案O(m log n)最适合同时处理两层优化目标。
BFS 分层后再二次最短路分阶段实现可做但实现分裂,直接维护二元组更统一。

最终代码与实现

Python 主实现

源文件:main.py

  • 实现状态:当前已有可执行实现
import heapq
import sys


def solve(data: str) -> str:
    tokens = list(map(int, data.split()))
    if not tokens:
        return ""
    it = iter(tokens)
    n = next(it)
    m = next(it)
    start = next(it)
    target = next(it)
    graph = [[] for _ in range(n + 1)]
    for _ in range(m):
        u = next(it)
        v = next(it)
        days = next(it)
        graph[u].append((v, days))
        graph[v].append((u, days))
    inf = (10 ** 18, 10 ** 18)
    dist = [inf] * (n + 1)
    prev = [-1] * (n + 1)
    dist[start] = (0, 0)
    heap = [(0, 0, start)]
    while heap:
        steps, days, node = heapq.heappop(heap)
        if (steps, days) != dist[node]:
            continue
        for nxt, cost in graph[node]:
            cand = (steps + 1, days + cost)
            if cand < dist[nxt]:
                dist[nxt] = cand
                prev[nxt] = node
                heapq.heappush(heap, (cand[0], cand[1], nxt))
    if dist[target] == inf:
        return "relay_count=-1\ntotal_days=-1\npath=IMPOSSIBLE"
    path = []
    cur = target
    while cur != -1:
        path.append(cur)
        cur = prev[cur]
    path.reverse()
    return "\n".join(
        [
            f"relay_count={dist[target][0]}",
            f"total_days={dist[target][1]}",
            f"path={'->'.join(map(str, path))}",
        ]
    )


if __name__ == "__main__":
    sys.stdout.write(solve(sys.stdin.read()).strip())
    sys.stdout.write("\n")

C++ 对照实现

源文件:main.cpp

  • 实现状态:当前已有可执行实现
#include <algorithm>
#include <iostream>
#include <limits>
#include <queue>
#include <string>
#include <utility>
#include <vector>

using namespace std;

struct State {
    int steps;
    int days;
    int node;
    bool operator>(const State& other) const {
        if (steps != other.steps) {
            return steps > other.steps;
        }
        return days > other.days;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, start, target;
    if (!(cin >> n >> m >> start >> target)) {
        return 0;
    }
    vector<vector<pair<int, int>>> graph(n + 1);
    for (int i = 0; i < m; ++i) {
        int u, v, days;
        cin >> u >> v >> days;
        graph[u].push_back({v, days});
        graph[v].push_back({u, days});
    }
    const pair<int, int> INF = {numeric_limits<int>::max() / 4, numeric_limits<int>::max() / 4};
    vector<pair<int, int>> dist(n + 1, INF);
    vector<int> prev(n + 1, -1);
    priority_queue<State, vector<State>, greater<State>> heap;
    dist[start] = {0, 0};
    heap.push({0, 0, start});
    while (!heap.empty()) {
        State cur = heap.top();
        heap.pop();
        if (make_pair(cur.steps, cur.days) != dist[cur.node]) {
            continue;
        }
        for (const auto& edge : graph[cur.node]) {
            int nxt = edge.first;
            int cand_steps = cur.steps + 1;
            int cand_days = cur.days + edge.second;
            pair<int, int> cand = {cand_steps, cand_days};
            if (cand < dist[nxt]) {
                dist[nxt] = cand;
                prev[nxt] = cur.node;
                heap.push({cand_steps, cand_days, nxt});
            }
        }
    }
    if (dist[target] == INF) {
        cout << "relay_count=-1\n";
        cout << "total_days=-1\n";
        cout << "path=IMPOSSIBLE\n";
        return 0;
    }
    vector<int> path;
    for (int cur = target; cur != -1; cur = prev[cur]) {
        path.push_back(cur);
    }
    reverse(path.begin(), path.end());
    cout << "relay_count=" << dist[target].first << "\n";
    cout << "total_days=" << dist[target].second << "\n";
    cout << "path=";
    for (size_t i = 0; i < path.size(); ++i) {
        if (i) {
            cout << "->";
        }
        cout << path[i];
    }
    cout << "\n";
    return 0;
}

代码执行与运行结果

最新成功运行

Run ID语言时间编译运行耗时(秒)输出终端记录
run-001py2026-03-30T23:44:33.308855+08:00000.03096outputtranscript
run-002cpp2026-03-30T23:44:33.852799+08:00000.021511outputtranscript

PY 运行输出摘录

relay_count=2
total_days=5
path=1->2->5

CPP 运行输出摘录

relay_count=2
total_days=5
path=1->2->5

全部运行记录索引

Run ID语言时间编译运行耗时(秒)输出终端记录
run-001py2026-03-30T23:44:33.308855+08:00000.03096outputtranscript
run-002cpp2026-03-30T23:44:33.852799+08:00000.021511outputtranscript

调试、修正与流程留痕

调试日志

源文件:debug-journal.md

症状假设实验结果下一步
样例输出与手算不一致终点不可达时必须按固定三行格式输出。逐步打印关键中间变量并对照题目公式确认中间量与题面一致后再整理最终输出将该类检查加入回归样例
边界输入触发错误分支同一节点可能被不同天数和不同换站次数重复到达,必须按二元组比较。构造最小规模或重复值数据进行单测补齐分支判断顺序把临界值加入验证计划
输出字段顺序或格式错误多项输出题容易在最后阶段拼接出错固定输出模板并逐项对照题面格式化输出统一稳定保留样例输出作为最终比对依据

失败案例目录

源文件:failure-catalog.md

编号风险点预防措施
1终点不可达时必须按固定三行格式输出。补充边界样例并在实现中显式处理
2同一节点可能被不同天数和不同换站次数重复到达,必须按二元组比较。补充边界样例并在实现中显式处理
3路径恢复时要注意起点前驱的终止标记。补充边界样例并在实现中显式处理

编码过程记录

源文件:implementation-journal.md

阶段改动原因
阶段 1需求整理把题目输入、输出和评分重点整理成结构化规格
阶段 2建模将题目翻译为 双关键字最短路 + 路径恢复 所需的数据结构
阶段 3实现分别完成 Python 主实现和需要的 C++ 对照实现
阶段 4校验用样例和边界数据核对输出,再汇总到完整档案

全流程文件导航

Official Prompt

正式题面全文

打开独立文件页

规则来源

  • 赛项说明页码:12-13
  • 训练题主题:丝路驿站传信:最少换站次数与最短耗时路径
  • 所属赛道:丝路文化赛道

题目背景

丝路传信任务需要从起点驿站把信息送到终点驿站。路线选择时先看换站次数是否最少,若换站次数相同,再比较总耗时。为了便于调度,还要恢复满足双关键字最优的完整路径。

任务描述

  • 读取驿站图并建立无向邻接表。
  • 先最小化经过的道路条数,也就是换站次数。
  • 在换站次数最少的前提下,再最小化总耗时,并输出完整路径。

输入格式

  1. 第一行输入 n m s t,表示驿站数、道路数、起点和终点。
  2. 接下来 m 行每行输入 u v days,表示一条无向道路及所需天数。

输出格式

  1. 可达时第一行输出 relay_count=最少换站次数
  2. 第二行输出 total_days=对应总天数
  3. 第三行输出 path= 后接 a->b->c 形式路径。
  4. 不可达时依次输出 relay_count=-1total_days=-1path=IMPOSSIBLE

数据范围与说明

  • 2 <= n <= 200。
  • 1 <= m <= 1000。
  • 1 <= days <= 50。
  • 答案保证按“换站次数最少,再总天数最少”后唯一。

样例输入

5 6 1 5
1 2 2
2 5 3
1 3 1
3 4 1
4 5 1
2 3 1

样例输出

relay_count=2
total_days=5
path=1->2->5

样例解释

  • 路径 1->2->5 只经过两条道路,因此换站次数为 2
  • 另一条 1->3->4->5 虽然总天数更短,但换站次数为 3,不满足主关键字最优。
  • 因此最终答案是 relay_count=2total_days=5

知识点清单

  • 邻接表建图。
  • 双关键字状态比较 (steps, days)
  • 优先队列维护最优状态。
  • 前驱数组恢复完整路径。
  • 不可达结果输出。
Rationale

解题思路全文

打开独立文件页

1. 问题重述

在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。

2. 数据结构与建模

  • 主算法:双关键字最短路 + 路径恢复
  • 输入拆解后对应的数据结构要和输出项一一对应。
  • 需要重点维护的状态包括:题目实体、核心指标、中间结果和最终答案。

3. 算法步骤

  1. 把每个节点的最优状态定义为 (换站次数, 总天数) 二元组。
  2. 用优先队列按字典序扩展当前最优状态。
  3. 若新状态字典序更小,就更新目标节点并记录前驱。
  4. 搜索结束后根据前驱数组恢复最优路径。

4. 正确性说明

  • 每一步都严格对应题面给出的规则或约束。
  • 所有输出字段都来自同一份计算过程,不会出现“各算各的”的不一致情况。
  • 边界情况通过单独分支或统一规则处理,保证程序在最小规模和重复值情况下也稳定。

5. 复杂度分析

  • 复杂度取决于输入规模和主算法,但整体设计保持在初中组可讲解、可验证的范围内。
  • 只保留必要状态,不引入超出题意的数据结构。

6. 易错点

  • 终点不可达时必须按固定三行格式输出。
  • 同一节点可能被不同天数和不同换站次数重复到达,必须按二元组比较。
  • 路径恢复时要注意起点前驱的终止标记。

7. 知识点清单

  • 邻接表建图。
  • 双关键字状态比较 (steps, days)
  • 优先队列维护最优状态。
  • 前驱数组恢复完整路径。
  • 不可达结果输出。
Delivery Summary

最终报告正文

打开独立文件页

题目概述

在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。

最终解法摘要

自动整理的解题流程

  • 题目主题:丝路驿站传信:最少换站次数与最短耗时路径
  • 题目摘要:在驿站图上先最小化换站次数,再最小化总天数,并恢复最优路径。
  • 判题提示:该题以优化求解为主,重点是约束建模、可行性检查和最优值维护。
  • 先完成输入、对象、约束和输出的四步建模,再落到具体算法和实现。
  • 优先用样例验证最小流程,再补边界测试和错误分支。

代码执行摘要

Run ID语言时间编译运行耗时(秒)输出终端记录
run-001py2026-03-30T23:44:33.308855+08:00000.03096outputtranscript
run-002cpp2026-03-30T23:44:33.852799+08:00000.021511outputtranscript

交付说明

本报告为摘要版,详细题目、题干、题解、最终代码、运行结果和调试流程已经汇总到完整解题档案中。

Case Files

文档与证据入口

7 sections

所有原始文件、样例、源码、调试记录和交付文档都保留在下方,便于从档案视图回落到仓库文件级证据。

运行证据

19 files