5318 【深基18.例3】查找文献
题目理解
这道题目要求我们对一个有向图进行DFS(深度优先搜索)和BFS(广度优先搜索)遍历,并按照特定规则输出遍历顺序。题目中的关键点包括:
-
图的构建:文章间的引用关系构成一个有向图
-
遍历规则:从文章1开始,当有多个可选文章时,优先选择编号较小的
-
输出要求:分别输出DFS和BFS的遍历顺序
解题思路
1. 图的表示
使用邻接表(vector<int> g[N])来存储图的边关系,因为:
-
文章编号范围是1到n(n ≤ 10^5)
-
边数m ≤ 10^6
-
邻接表适合稀疏图且空间效率高
2. 处理输入
读取n和m后,读取m条边关系,构建邻接表:
while(m--) {
int u, v;
cin >> u >> v;
g[u].push_back(v); // 添加u→v的边
}
3. 邻接表排序
题目要求"先看编号较小的那篇",因此需要对每个节点的邻接表进行排序:
for(int i = 1; i <= n; i++) {
sort(g[i].begin(), g[i].end());
}
这一步确保在DFS和BFS时,总是优先访问编号较小的节点。
4. DFS实现
深度优先搜索采用递归实现:
void dfs(int x) {
vis[x] = 1; // 标记已访问
cout << x << " "; // 输出当前节点
for(int v : g[x]) { // 遍历邻接节点
if(vis[v] == 0) { // 如果未访问
dfs(v); // 递归访问
}
}
}
特点:尽可能深地探索图的分支,适合发现图的深层结构。
5. BFS实现
广度优先搜索使用队列实现:
void bfs(int x) {
queue<int> q;
q.push(x); // 初始节点入队
vis[x] = 1; // 标记已访问
cout << x << " "; // 输出当前节点
while(!q.empty()) {
int u = q.front(); // 取出队首
q.pop();
for(int v : g[u]) { // 遍历邻接节点
if(vis[v] == 0) { // 如果未访问
cout << v << " "; // 输出节点
vis[v] = 1; // 标记已访问
q.push(v); // 入队等待处理
}
}
}
}
特点:按层次遍历图,适合寻找最短路径。
6. 主函数流程
int main() {
// 输入处理
// 邻接表排序
dfs(1); // 从文章1开始DFS
cout << endl; // 换行分隔
memset(vis, 0, sizeof(vis)); // 重置访问标记
bfs(1); // 从文章1开始BFS
return 0;
}
代码注释详解
#include<bits/stdc++.h>
#define N 100005 // 定义最大节点数
#define endl "\n"
using namespace std;
int n, m; // 文章数和引用关系数
vector<int> g[N]; // 邻接表存储图
bool vis[N]; // 访问标记数组
// 深度优先搜索
void dfs(int x) {
vis[x] = 1; // 标记当前节点已访问
cout << x << " "; // 输出当前节点
for(int v : g[x]) { // 遍历所有邻接节点
if(vis[v] == 0) { // 如果邻接节点未被访问
dfs(v); // 递归访问
}
}
}
// 广度优先搜索
void bfs(int x) {
queue<int> q; // 创建队列
q.push(x); // 起始节点入队
vis[x] = 1; // 标记已访问
cout << x << " "; // 输出起始节点
while(!q.empty()) { // 队列不为空时循环
int u = q.front(); // 获取队首元素
q.pop(); // 队首出队
for(int v : g[u]) { // 遍历当前节点的邻接节点
if(vis[v] == 0) { // 如果邻接节点未被访问
cout << v << " "; // 输出节点
vis[v] = 1; // 标记已访问
q.push(v); // 邻接节点入队
}
}
}
}
int main() {
cin >> n >> m; // 输入文章数和引用关系数
while(m--) { // 处理每条引用关系
int u, v;
cin >> u >> v;
g[u].push_back(v); // 构建邻接表
}
// 对每个节点的邻接表排序,确保优先访问编号小的文章
for(int i = 1; i <= n; i++) {
sort(g[i].begin(), g[i].end());
}
dfs(1); // 执行DFS
cout << endl; // 换行
memset(vis, 0, sizeof(vis)); // 重置访问标记数组
bfs(1); // 执行BFS
return 0;
}
复杂度分析
-
时间复杂度:
-
邻接表排序:O(n + m log d),其中d是平均出度
-
DFS/BFS:O(n + m)
-
总体:O(n + m log d)
-
-
空间复杂度:
-
邻接表存储:O(n + m)
-
访问数组:O(n)
-
队列/递归栈:最坏O(n)
-

浙公网安备 33010602011771号