当前位置: 首页 > news >正文

查找文献

题目描述

小 K 喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的博客文章。小 K 求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考文献的话就不用再看它了)。

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

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

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

输入格式

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

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

输出格式

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

输入数据 1

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

输出数据 1

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

这道题是典型的图遍历问题,需要我们对有向图分别两种经典遍历:深度优先搜索 (DFS) 和广度优先搜索 (BFS)。下面我将分步骤详细讲解解题思路和完整的 C++ 实现代码。

问题分析

  • 有 n 篇文章 (节点) 和 m 条引用关系 (有向边)
  • 从文章 1 开始,需要访问所有可达的文章
  • 当有多个可选文章时,优先访问编号小的
  • 分别输出 DFS 和 BFS 的遍历结果

解决方案步骤

步骤 1:数据结构选择
  • 使用邻接表存储图结构:适合表示稀疏图,效率高
  • 使用布尔数组标记节点是否已访问
步骤 2:输入处理与图构建
  • 读取 n 和 m
  • 读取 m 条边,构建邻接表
  • 对每个节点的邻接列表排序,确保按编号升序访问
步骤 3:实现 DFS 算法
  • 递归实现:访问当前节点→标记已访问→递归访问所有未访问的邻居
步骤 4:实现 BFS 算法
  • 使用队列实现:将节点入队→出队访问→将所有未访问的邻居入队
步骤 5:输出结果
  • 先输出 DFS 结果,再输出 BFS 结果

完整 C++ 代码实现

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;// 定义最大节点数,根据题目约束n≤105
const int MAXN = 100005;// 邻接表:adj[x]存储x的所有引用文献(邻居节点)
vector<int> adj[MAXN];
// 访问标记数组:记录节点是否已被访问
bool visited[MAXN];// 深度优先搜索实现
void dfs(int u) {// 标记当前节点为已访问visited[u] = true;// 输出当前节点cout << u << " ";// 遍历所有邻居节点(已排序)for (int v : adj[u]) {// 如果邻居未被访问,则递归访问if (!visited[v]) {dfs(v);}}
}// 广度优先搜索实现
void bfs(int start) {// 创建队列并将起始节点入队queue<int> q;q.push(start);// 标记起始节点为已访问visited[start] = true;// 队列非空时循环while (!q.empty()) {// 取出队首节点int u = q.front();q.pop();// 输出当前节点cout << u << " ";// 遍历所有邻居节点for (int v : adj[u]) {// 如果邻居未被访问if (!visited[v]) {// 标记为已访问并加入队列visited[v] = true;q.push(v);}}}
}int main() {// 读取节点数n和边数mint n, m;cin >> n >> m;// 读取m条边,构建邻接表for (int i = 0; i < m; i++) {int x, y;cin >> x >> y;// 添加有向边x->yadj[x].push_back(y);}// 对每个节点的邻居列表进行排序// 确保在有多个选择时,优先访问编号小的节点for (int i = 1; i <= n; i++) {sort(adj[i].begin(), adj[i].end());}// 执行DFS并输出结果// 先重置访问标记数组fill(visited, visited + n + 1, false);dfs(1);cout << endl;// 执行BFS并输出结果// 再次重置访问标记数组fill(visited, visited + n + 1, false);bfs(1);cout << endl;return 0;
}

代码分步讲解

  1. 数据结构定义

  • const int MAXN = 100005;
    vector<int> adj[MAXN];  // 邻接表存储图
    bool visited[MAXN];     // 访问标记数组
    
    • MAXN 定义了最大节点数,满足题目 n≤105 的要求
    • adj 是邻接表,adj [x] 存储所有被 x 引用的文献
    • visited 数组标记标记节点是否已访问
  • DFS 实现

  • void dfs(int u) {visited[u] = true;    // 标记当前节点为已访问cout << u << " ";     // 输出当前节点for (int v : adj[u]) {  // 遍历所有邻居if (!visited[v]) {    // 若邻居未访问dfs(v);        // 递归访问}}
    }
    
    • 递归思想:先访问当前节点,再深入访问每个未访问的邻居
    • 由于邻居列表已排序,保证了按编号升序访问
  • BFS 实现

  • void bfs(int start) {queue<int> q;q.push(start);         // 起始点入队visited[start] = true; // 标记为已访问while (!q.empty()) {int u = q.front(); // 取出队首q.pop();cout << u << " ";  // 输出for (int v : adj[u]) {if (!visited[v]) {visited[v] = true;q.push(v); // 未访问的邻居入队}}}
    }
    
    • 队列思想:按层次访问,先访问完当前层再进入下一层
    • 同样利用已排序的邻居列表保证访问顺序
  • 主函数流程

  1. int main() {// 1. 读取输入cin >> n >> m;for (int i = 0; i < m; i++) {int x, y;cin >> x >> y;adj[x].push_back(y);}// 2. 排序邻居列表for (int i = 1; i <= n; i++) {sort(adj[i].begin(), adj[i].end());}// 3. 执行DFSfill(visited, visited + n + 1, false);dfs(1);cout << endl;// 4. 执行BFSfill(visited, visited + n + 1, false);bfs(1);cout << endl;return 0;
    }
    
    • 读取输入并构建邻接表
    • 关键步骤:对每个节点的邻居排序,确保按编号升序访问
    • 分别执行 DFS 和 BFS,每次执行前重置 visited 数组

通过这个实现,我们完美解决了问题要求:从文章 1 开始,不重复不遗漏地访问所有可达文章,并按编号升序选择下一篇文章,分别输出 DFS 和 BFS 的遍历结果。

http://www.dtcms.com/a/311245.html

相关文章:

  • 类似 Pixso 但更侧重「网页 / 软件界面设计」「前后端可视化开发」的工具
  • 【智能体cooragent】_process_workflow 结构拆解分析
  • 一维dp-序列类型-最长有效括号
  • XGBoost三部曲:XGBoost参数详解
  • 机械臂的轨迹生成的多种方案
  • 信号完整性、电源完整性与电磁兼容的含义
  • Removing Digits(Dynamic Programming)
  • SEA-RAFT:更简单、更高效、更准确的RAFT架构
  • 人工智能与交通:智能出行的变革与未来
  • OneCode 3.0表达式从语法到执行的全链路设计
  • 解锁智能油脂润滑系统:加速度与温振传感器选型协同攻略
  • 【隧道篇 / IPsec】(7.6) ❀ 02. 如何删除向导创建的IPsec安全隧道 (点对点) ❀ FortiGate 防火墙
  • 阿里云:Ubuntu系统部署宝塔
  • 【Go语言-Day 29】从time.Now()到Ticker:Go语言time包实战指南
  • eSIM技术深度解析:从物理芯片到数字革命
  • SAP 标准代码测试OO ALV案例分享
  • ubuntu22.04离线一键安装gpu版docker
  • Unity —— Android 应用构建与发布​
  • 社群团购市场选择与开源技术赋能下的下沉市场开拓策略研究——以开源AI智能名片、链动2+1模式与S2B2C商城小程序为例
  • 苹果MAC 安卓模拟器
  • 2561. 重排水果
  • 48Days-Day12 | 添加字符,数组变换,装箱问题
  • 2025牛客暑期多校训练营1(G,E,L,K,I)
  • 力扣 hot100 Day63
  • (LeetCode 面试经典 150 题) 138. 随机链表的复制 (哈希表)
  • Jupyter notebook如何显示行号?
  • 邮科工业交换机:互联网世界的“隐形守护者”
  • 【DL学习笔记】计算图与自动求导
  • K8S部署ELK(一):部署Filebeat日志收集器
  • 红黑树(RBTree)