📌  相关文章
📜  教资会网络 | UGC NET CS 2015 年 12 月 – II |问题 11(1)

📅  最后修改于: 2023-12-03 14:54:48.714000             🧑  作者: Mango

教资会网络 | UGC NET CS 2015 年 12 月 - II | 问题 11

这道题涉及到数据结构和算法中的树的遍历,需要使用深度优先遍历(DFS)和广度优先遍历(BFS)两种方式完成。

题目描述

给定一棵树,树的编号为1~n。每个节点有一个权值Weight[i],权值均为正整数。现在,按照以下两种方式对树进行遍历:

  • 深度优先遍历:首先到达编号最小的节点,然后挑选权值前两大的子节点进行深度优先遍历,以此类推。
  • 广度优先遍历:首先到达编号最小的节点,然后挑选权值前两大的子节点进行广度优先遍历,以此类推。

求这两种情况下的遍历顺序。

解题思路

首先,树的遍历可以用DFS和BFS两种方式实现。定义一个visited数组表示当前节点是否访问过,以及一个max1max2数组表示当前节点的子节点权值的前两大值。

对于DFS遍历,可以首先排序整个树,保证每次遍历到的节点是权值最小的,然后从根节点开始,遍历每个节点,并使用递归实现子树的遍历。每遍历到一个节点,就按照权值对其子节点进行排序,然后优先遍历权值最大的两个子节点,并继续递归。

对于BFS遍历,同样可以从编号最小的点开始,使用一个priority_queue对每个节点的子节点进行排序,每次取出权值最大的两个子节点,并将其加入队列。然后继续下一层的遍历。

最后,输出DFS和BFS的遍历结果。

代码实现
### DFS遍历

- 全局变量:visited[], max1[], max2[]
- 函数名:void dfs(int i)
- 函数功能:DFS遍历整个树,并求出每个节点的权值前两大的子节点
- 入参:i表示当前节点的编号
- 使用方法:从根节点开始调用

代码:

void dfs(int i) {
    visited[i] = true;
    priority_queue<int> q;

    // 遍历当前节点的所有子节点
    for (int j = head[i]; j != -1; j = e[j].next) {
        int v = e[j].to;
        if (!visited[v]) {
            dfs(v);
            q.push(max1[v]);
            q.push(max2[v]);
        }
    }

    // 取出当前节点的前两大子节点
    int cnt = 0;
    while (!q.empty() && cnt < 2) {
        int p = q.top();
        q.pop();

        if (p > 0) {
            cnt++;
            if (max1[i] < p) {
                max2[i] = max1[i];
                max1[i] = p;
            } else if (max2[i] < p) {
                max2[i] = p;
            }
        }
    }
}

### BFS遍历

- 全局变量:visited[], max1[], max2[]
- 函数名:void bfs(int i)
- 函数功能:BFS遍历整个树,并求出每个节点的权值前两大的子节点
- 入参:i表示从哪个节点开始遍历
- 使用方法:从根节点开始调用

代码:

void bfs(int i) {
    queue<int> q;
    q.push(i);

    while (!q.empty()) {
        int u = q.front();
        q.pop();

        visited[u] = true;
        priority_queue<int> pq;

        // 对当前节点的子节点进行排序,并加入优先队列
        for (int j = head[u]; j != -1; j = e[j].next) {
            int v = e[j].to;
            if (!visited[v]) {
                pq.push(e[j].w);
            }
        }

        // 取出当前节点的前两大子节点
        int cnt = 0;
        while (!pq.empty() && cnt < 2) {
            int p = pq.top();
            pq.pop();

            if (p > 0) {
                cnt++;
                if (max1[u] < p) {
                    max2[u] = max1[u];
                    max1[u] = p;
                } else if (max2[u] < p) {
                    max2[u] = p;
                }
            }
        }

        // 将当前节点的子节点加入队列
        for (int j = head[u]; j != -1; j = e[j].next) {
            int v = e[j].to;
            if (!visited[v]) {
                q.push(v);
            }
        }
    }
}

## 参考资料

- 《算法竞赛入门经典》