news 2026/4/16 10:39:19

查找文献(信息学奥赛一本通- P2125)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
查找文献(信息学奥赛一本通- P2125)

【题目描述】

当我们阅读文章时,每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的文章。如果小Q他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考文献的话就不用再看它了)。

假设图书室里面一共有 n(n≤105) 篇文章(编号为 1 到 n)以及 m(m≤106) 条参考文献引用关系。目前小 Q 已经开始阅读编号为 1 的一篇文章,请帮助小Q设计一种方法,使小Q可以不重复、不遗漏的看完所有他能看到的文章。

这边是已经整理好的参考文献关系图,其中,文献 X → Y 表示文章 X 有参考文献 Y。不保证编号为 1 的文章没有被其他文章引用。

请对这个图分别进行 DFS 和 BFS,并输出遍历结果。如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序)。

【输入】

共 m+1 行,第 1 行为 2 个数,n 和 m,分别表示一共有 n(n≤105) 篇文章(编号为 1 到 n)以及m(m≤106) 条参考文献引用关系。

接下来 m 行,每行有两个整数 X,Y 表示文章 X 有参考文献 Y。

【输出】

共 2 行。

第一行为 DFS 遍历结果,第二行为 BFS 遍历结果。

【输入样例】

8 9 1 2 1 3 1 4 2 5 2 6 3 7 4 7 4 8 7 8

【输出样例】

1 2 5 6 3 7 8 4 1 2 3 4 5 6 7 8
1. 解题思路

这道题的核心难点不在于 DFS 或 BFS 的原理,而在于如何控制遍历顺序

题目通常要求:当一个点有多个邻居时,必须优先访问编号较小的那个(即字典序最小)。

  • 如果用vector存图:非常简单,把每个点的邻居vector拿出来sort一遍就行。

  • 如果用链式前向星:这里有要注意的

    • 链式前向星是“头插法”。

    • 这意味着:后加入的边,会排在链表的最前面。(如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序))题目中告诉我们需要排序

    • 举例:如果按顺序加入边1->21->3,链表里实际的存储顺序是1->3->2。遍历时会先走 3,再走 2。导致答案错误。

解决方案:既然链式前向星会把顺序“倒过来”,那我们在存图之前,先把数据倒着排。

  • 排序规则

    1. 起点u从小到大(这就不用说了,为了按顺序处理点)。

    2. 终点v从大到小(这样倒着插进去,输出出来就是从小到大了)。

  • 效果:

    比如有边 (1, 2) 和 (1, 5)。排序后让 (1, 5) 排在 (1, 2) 前面。

    • 先存(1, 5)-> 表头是 5。

    • 再存(1, 2)-> 2 插到 5 前面 -> 表头是 2 -> 链表变成2 -> 5

    • 遍历时:先访问 2,再访问 5。完美符合题目要求。


2. 完整代码
#include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; int h[100010]; int vtex[1000010]; int nxt[1000010]; int idx; int vis1[1000010];//dfs标记数组 int vis2[1000010];//bfs标记数组 queue<int>q; struct gen{ int u; int v; }a[1000005]; //先按照起点从小到大排序,再按照终点从大到小排序(因为链式前向星是倒着存进去的,所以我们要从大到小排序终点) bool cmp(gen c,gen d){ if(c.u!=d.u) return c.u<d.u; else return c.v>d.v; } void bfs(int x){ q.push(x); while(!q.empty()){ int tmp=q.front(); cout<<tmp<<" "; q.pop(); int p=h[tmp]; while(p!=-1){//不是空指针 int tmp=vtex[p]; if(vis2[tmp]==0){//说明该点没有入队过 vis2[tmp]=1;//打上标记 q.push(tmp);//入队 } p=nxt[p];//指针指向当前指针所指向数的下一个数 } } } void dfs(int x){ cout<<x<<" "; int p=h[x]; while(p!=-1){//如果指针不指向空 if(vis1[vtex[p]]==0){//如果指针指向的点没有走过 vis1[vtex[p]]=1;//打上标记 dfs(vtex[p]);//把指针指向的点作为下一个起点继续走 } p=nxt[p];//找p指针指向点的下一个点 } } void addedge(int x,int y){ vtex[idx]=y; nxt[idx]=h[x]; h[x]=idx++; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,m; cin>>n>>m; //先把关系存进a数组 for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; a[i].u=x; a[i].v=y; } //如果有很多篇文章可以参阅,先看编号较小的那篇(所以需要先a数组排序 sort(a+1,a+m+1,cmp); memset(h,-1,sizeof(h));//初始化h数组 //邻接表存图 for(int i=1;i<=m;i++) addedge(a[i].u,a[i].v); vis1[1]=1;//把起点打上标记 dfs(1); cout<<endl; vis2[1]=1;//把起点打上标记 bfs(1); return 0; }
3. 总结
  • 存图顺序:在使用链式前向星时,如果题目对遍历顺序有要求(如字典序),必须先对边排序

  • 排序方式起点升序,终点降序

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 3:44:25

一个实例用全创建型模式-优化(冗余消除)

1.关联链接 上一篇&#xff1a;一个实例用全创建型模式-CSDN博客 目录&#xff1a;《一个实例讲完23种设计模式》 2.内容 当前&#xff1a;单件抽象工厂创建者工厂方法优化 需求&#xff1a;坦克大战 创建两种坦克 坦克类型 射程 速度 b70 70米 时/70公里…

作者头像 李华
网站建设 2026/4/14 16:38:52

SSH隧道转发TensorBoard端口:本地可视化远程训练指标

SSH隧道转发TensorBoard端口&#xff1a;本地可视化远程训练指标 在深度学习的实际开发中&#xff0c;一个再熟悉不过的场景是&#xff1a;你在办公室或家里的笔记本上敲代码&#xff0c;而真正的“算力战场”却远在数据中心的一台搭载A100的服务器上。模型正在那里安静地训练…

作者头像 李华
网站建设 2026/4/13 14:44:49

GitHub Release发布正式版PyTorch模型权重文件

PyTorch-CUDA-v2.8 镜像&#xff1a;从模型权重到可复现环境的一体化交付 在深度学习项目中&#xff0c;你是否经历过这样的场景&#xff1f; 同事发来一个“训练好的模型权重”&#xff0c;你兴冲冲地下载下来准备推理测试&#xff0c;结果运行第一行代码就报错&#xff1a;CU…

作者头像 李华
网站建设 2026/4/11 7:59:13

清华镜像站同步频率解析:确保PyTorch包版本最新

清华镜像站同步频率解析&#xff1a;确保PyTorch包版本最新 在人工智能研发一线&#xff0c;你是否曾经历过这样的场景&#xff1a;深夜调试模型&#xff0c;pip install torch 却卡在 30% 进度条上动弹不得&#xff1f;或者团队成员因 PyTorch 版本不一致导致实验结果无法复现…

作者头像 李华
网站建设 2026/4/15 14:46:29

PyTorch-CUDA-v2.8镜像资源调度优化方向探讨

PyTorch-CUDA-v2.8镜像资源调度优化方向探讨 在当前深度学习项目日益复杂、训练任务频繁迭代的背景下&#xff0c;一个稳定、高效且可复用的运行时环境已成为研发流程中的关键基础设施。尤其是在多团队协作、GPU集群共享或持续集成&#xff08;CI/CD&#xff09;场景下&#xf…

作者头像 李华
网站建设 2026/4/15 8:12:20

DTD 元素

DTD 元素 概述 DTD(Document Type Definition,文档类型定义)是XML文档的骨架,它定义了XML文档的结构、元素、属性和它们的约束关系。DTD是一种简单的XML文档声明,用于描述XML文档的结构。它主要被用于定义XML文档的类型,确保XML文档的合法性。 DTD的基本结构 一个DTD…

作者头像 李华