CCF-CSP 202212-2 训练计划:拓扑排序双图解法,15ms 100分代码详解

发布时间:2026/9/9 14:29:55

CCF-CSP 202212-2 训练计划:拓扑排序双图解法,15ms 100分代码详解 CCF-CSP 202212-2 训练计划拓扑排序双图解法与高效实现策略在CCF-CSP认证考试中第二题往往考察考生对基础算法和数据结构灵活应用的能力。2022年12月的第二题训练计划就是一个典型的需要拓扑排序技巧的问题。本文将深入解析如何利用正反双图拓扑排序来计算任务的最早和最晚开始时间并提供一份15ms内完成的高效C实现代码。1. 问题分析与建模训练计划问题可以抽象为一个有向无环图(DAG)的任务调度模型。每个训练科目对应图中的一个节点科目间的依赖关系构成图中的有向边。题目要求我们计算两项关键指标最早开始时间每个任务在所有前置任务完成后能够开始的最早时间最晚开始时间在不影响总工期的前提下每个任务可以开始的最晚时间1.1 输入数据解析输入包含三行关键信息第一行n总天数和m科目数量第二行m个整数表示每个科目依赖的前置科目0表示无依赖第三行m个正整数表示每个科目需要的训练天数int n, m; cin n m; vectorint p(m1), t(m1); for(int i1; im; i) cin p[i]; for(int i1; im; i) cin t[i];1.2 图结构构建我们需要构建两种图表示正向图用于计算最早开始时间边u→v表示v依赖于u反向图用于计算最晚开始时间边v→u表示u被v依赖vectorvectorint g(m1), ginv(m1); vectorint in(m1), out(m1); for(int i1; im; i) { if(!p[i]) continue; g[p[i]].push_back(i); // 正向图 in[i]; // 入度统计 ginv[i].push_back(p[i]); // 反向图 out[p[i]]; // 出度统计 }2. 拓扑排序与时间计算2.1 最早开始时间计算最早开始时间采用正向拓扑排序初始化所有无依赖任务的开始时间为1然后按照拓扑序递推vectorint mn(m1); queueint q; for(int i1; im; i) { if(!in[i]) { mn[i] 1; // 无依赖任务第1天开始 q.push(i); } } int max_end 0; while(!q.empty()) { int u q.front(); q.pop(); for(int v : g[u]) { mn[v] max(mn[v], mn[u] t[u]); // 关键递推式 if(--in[v] 0) q.push(v); } max_end max(max_end, mn[u] t[u] - 1); }2.2 可行性检查与最晚时间计算在计算最晚时间前需要检查所有任务是否能在n天内完成if(max_end n) { // 只输出最早时间 for(int i1; im; i) cout mn[i] \n[im]; return; }最晚开始时间采用反向拓扑排序初始化所有不被依赖的任务的最晚开始时间为n - t[i] 1vectorint mx(m1, INF); for(int i1; im; i) { if(!out[i]) { mx[i] n - t[i] 1; // 最后时刻开始 q.push(i); } } while(!q.empty()) { int u q.front(); q.pop(); for(int v : ginv[u]) { mx[v] min(mx[v], mx[u] - t[v]); // 关键递推式 if(--out[v] 0) q.push(v); } }3. 完整代码实现与优化以下是整合了所有优化技巧的完整实现包含输入输出优化和简洁的逻辑处理#include bits/stdc.h using namespace std; const int INF 0x3f3f3f3f; void solve() { int n, m; cin n m; vectorint p(m1), t(m1); for(int i1; im; i) cin p[i]; for(int i1; im; i) cin t[i]; // 建图及统计度数 vectorvectorint g(m1), ginv(m1); vectorint in(m1), out(m1); for(int i1; im; i) { if(!p[i]) continue; g[p[i]].push_back(i); in[i]; ginv[i].push_back(p[i]); out[p[i]]; } // 计算最早开始时间 vectorint mn(m1); queueint q; for(int i1; im; i) { if(!in[i]) { mn[i] 1; q.push(i); } } int max_end 0; while(!q.empty()) { int u q.front(); q.pop(); for(int v : g[u]) { mn[v] max(mn[v], mn[u] t[u]); if(--in[v] 0) q.push(v); } max_end max(max_end, mn[u] t[u] - 1); } // 输出最早时间 for(int i1; im; i) cout mn[i] \n[im]; // 检查可行性 if(max_end n) return; // 计算最晚开始时间 vectorint mx(m1, INF); for(int i1; im; i) { if(!out[i]) { mx[i] n - t[i] 1; q.push(i); } } while(!q.empty()) { int u q.front(); q.pop(); for(int v : ginv[u]) { mx[v] min(mx[v], mx[u] - t[v]); if(--out[v] 0) q.push(v); } } // 输出最晚时间 for(int i1; im; i) cout mx[i] \n[im]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); solve(); return 0; }4. 算法复杂度与优化分析4.1 时间复杂度该算法的时间复杂度主要由以下部分组成建图O(m)正向拓扑排序O(m)反向拓扑排序O(m)总时间复杂度为O(m)非常高效可以轻松处理题目给出的m≤100的限制。4.2 空间复杂度空间消耗主要来自存储正向图和反向图O(m)存储入度和出度数组O(m)存储最早和最晚时间数组O(m)总空间复杂度也是O(m)。4.3 关键优化技巧双图结构同时维护正向图和反向图避免重复计算依赖关系拓扑排序队列复用使用同一个队列进行正反两次拓扑排序输入输出优化使用ios::sync_with_stdio(false)加速IO边界条件处理及时检查总工期是否满足要求5. 常见错误与调试技巧在实现这类拓扑排序问题时容易出现以下几种典型错误环状依赖检测虽然题目保证依赖关系合法但在实际应用中需要检测环时间计算错误注意开始时间和结束时间的转换结束时间开始时间持续时间-1初始化遗漏忘记初始化无依赖任务的最早开始时间为1反向图构建错误容易混淆边的方向调试时可以打印中间结果如图结构、度数数组对小样例手动计算验证检查边界条件如所有任务都无依赖的情况// 调试打印图结构示例 void printGraph(const vectorvectorint g) { for(int u1; ug.size(); u) { cout u : ; for(int v : g[u]) cout v ; cout endl; } }6. CSP考试实战建议针对CCF-CSP认证考试中的类似问题建议采取以下策略快速建模迅速将实际问题转化为图论模型模板准备提前准备好拓扑排序等常用算法的模板代码分步验证先确保部分正确性如最早时间计算正确时间管理第二题通常需要30-45分钟内完成极端测试考虑m1、所有任务无依赖等边界情况提示在考试中如果时间紧张可以先确保最早时间的计算正确这部分通常占50%的分数。最晚时间的计算可以作为加分项。7. 扩展应用与变种思考这种双图拓扑排序的方法不仅适用于训练计划问题还可以解决许多类似的调度问题课程安排计算课程的最早和最晚开课时间项目计划确定关键路径和任务浮动时间依赖解析软件包管理中的依赖关系处理并行任务调度确定任务的最优执行顺序变种问题可能包括带权重的依赖关系任务间的多种约束类型资源限制下的调度动态依赖关系变化掌握这种双图拓扑排序的思想能够帮助我们在面对复杂依赖关系时高效计算出各项任务的时间窗口为决策提供有力支持。
延伸阅读

更多相关文章

2026/9/7 14:27:08

如何优化4D-RGPT-8B性能:10个GPU加速与推理优化技巧

如何优化4D-RGPT-8B性能:10个GPU加速与推理优化技巧 【免费下载链接】4D-RGPT-8B 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/4D-RGPT-8B 4D-RGPT-8B是NVIDIA开发的革命性多模态大语言模型,专门用于4D视频理解和区域级推理任务。作为N…

2026/9/9 16:02:54

AMD-Quark量化实战:如何将Kimi-K2.5转换为W4A8格式

AMD-Quark量化实战:如何将Kimi-K2.5转换为W4A8格式 【免费下载链接】Kimi-K2.5-W4A8 项目地址: https://ai.gitcode.com/hf_mirrors/amd/Kimi-K2.5-W4A8 Kimi-K2.5是一款功能强大的多模态模型,支持文本和视觉处理。通过AMD-Quark量化技术将其转换…

2026/9/10 8:57:00

Android MediaPlayer.setPreferredDevice 音频路由切换完全指南

做音频开发的兄弟应该都有这种经历:同一个视频源,在扬声器外放和蓝牙耳机上听完全是两个效果。如果你正好在做音乐播放器、视频客户端或者投屏工具,肯定被“怎么让 MediaPlayer 把声音输出到指定设备”这个需求折磨过。今天这篇是Android进阶…

2026/9/10 8:57:00

R-Studio数据恢复实战:误删、格式化与分区损坏的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 8:57:00

GeoPandas实战:Shapefile文件解析与坐标系核验完整指南

简介:四川省地表水水质国控断面坐标数据包含93个断面,覆盖省内主要河流与流域,以GIS矢量文件形式提供,面向环境监测、水资源管理及地理信息分析人员,可用于断面精确定位、水质监测网络可视化与区域对比研究。压缩包共8…

2026/9/10 8:56:59

TAS5760MDCAR车规D类功放深度解析:EMI抑制与热可靠性设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 8:51:59

CUDA程序浮点结果不一致?CCCL确定性方案全解析

做CUDA开发这么多年,踩过最隐蔽的坑之一就是“同一个程序,两次运行结果对不上”。不是那种差几千万的错,而是小数点后第6位、第7位开始飘。你要是做图形渲染、游戏引擎,这根本无所谓;做数值计算、科学计算、机器学习训…

2026/9/9 13:11:35

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/8 7:15:15

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/7 22:46:00

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/9 10:21:54

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码