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号
浙公网安备 33010602011771号