树上好点问题 - C++ 代码实现与优化

问题描述:

给定一棵树,其 N 个顶点的编号为 1 到 N 。第 i 条边连接顶点 A[i] 和顶点 B[i] 。顶点 i 的颜色为 C[i] 。如果从顶点 1 到顶点 x 的路径上(最短路径),不包含与点 x 相同颜色的点(顶点 x 本身除外),我们称顶点 x 为好点。按照升序输出所有好点。

输入:

第一行输入一个正整数 N,表示顶点的数量。 第二行输入 N 个正整数 C[i],分别表示每个点的颜色。 之后 N-1 行,每行输入两个正整数 A[i],B[i] 表示一条树边。 其中 2≤N≤1e5,1≤C[i]≤1e5,保证给定的图是一棵树。

输出:

输出使用换行符作为分隔符,按升序输出所有好点的编号。

样例输入:

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

样例输出:

1
2
3
4
6

数据范围限制:

  • 对于 17% 的数据, 2 ≤ N ≤ 10 ;
  • 对于 33% 的数据, 2 ≤ N ≤ 3000 ;
  • 对于 100% 的数据, 2 ≤ N ≤ 10^5 ,1 ≤ C[i] ≤ 10^5 ,1 ≤ A[i],B[i] ≤ N ,保证给定的图是一棵树。

使用 C++。

思路:

首先需要构建一棵树,可以使用邻接表来表示图。然后从根节点开始进行深度优先搜索,对每个节点进行判断,如果满足条件(即该节点与路径上的节点颜色不相同),则将其加入到好点集合中。最后对好点集合进行排序,按照升序输出。

具体实现步骤如下:

  1. 定义一个结构体 Node,表示每个节点,包括节点编号、颜色和邻接表。
  2. 定义一个 vector 数组 nodes,用来存储所有节点信息。
  3. 定义一个 vector 数组 goodNodes,用来存储所有好点的编号。
  4. 定义一个 bool 数组 visited,用来标记节点是否被访问过。
  5. 定义一个函数 dfs,用来进行深度优先搜索。在 dfs 函数中,首先将当前节点标记为已访问,然后对当前节点的邻接表进行遍历,对于每个邻接节点,如果其颜色与当前路径上的节点颜色不相同,则将其加入到好点集合中,并递归调用 dfs 函数。
  6. 在主函数中,首先读入输入数据,构建树。然后调用 dfs 函数进行深度优先搜索,并将所有好点的编号保存到 goodNodes 数组中。最后对 goodNodes 数组进行排序,并按照升序输出。

时间复杂度分析:

  • 构建树的时间复杂度为 O(N)。
  • 深度优先搜索的时间复杂度为 O(N)。
  • 排序的时间复杂度为 O(NlogN)。

总的时间复杂度为 O(NlogN)。

空间复杂度分析:

  • 邻接表的空间复杂度为 O(N)。
  • visited 数组的空间复杂度为 O(N)。
  • goodNodes 数组的空间复杂度为 O(N)。

总的空间复杂度为 O(N)。

代码实现如下:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 节点结构体
struct Node {
    int id; // 节点编号
    int color; // 节点颜色
    vector<int> adj; // 邻接表
};

int main() {
    int n; // 顶点数量
    cin >> n;

    // 存储所有节点信息
    vector<Node> nodes(n + 1); 
    for (int i = 1; i <= n; i++) {
        nodes[i].id = i; // 设置节点编号
        cin >> nodes[i].color; // 输入节点颜色
    }

    // 构建树
    for (int i = 1; i < n; i++) {
        int a, b;
        cin >> a >> b;
        nodes[a].adj.push_back(b);
        nodes[b].adj.push_back(a);
    }

    // 存储所有好点的编号
    vector<int> goodNodes;
    // 标记节点是否被访问过
    vector<bool> visited(n + 1, false);

    // 深度优先搜索函数
    void dfs(int cur, int prevColor) {
        visited[cur] = true;
        // 判断当前节点是否为好点
        if (cur != 1 && nodes[cur].color != prevColor) {
            goodNodes.push_back(cur);
        }
        // 遍历当前节点的邻接节点
        for (int next : nodes[cur].adj) {
            if (!visited[next]) {
                dfs(next, nodes[cur].color);
            }
        }
    }

    // 从根节点开始深度优先搜索
    dfs(1, -1); // 初始颜色设置为 -1

    // 对好点集合进行排序
    sort(goodNodes.begin(), goodNodes.end());

    // 输出所有好点的编号
    for (int node : goodNodes) {
        cout << node << endl;
    }

    return 0;
}

代码优化建议:

  • 可以使用 vector 的 resize 函数来预先分配好节点数组 nodes 的内存空间,避免在循环中多次进行内存分配,提高效率。
  • 可以使用 map 存储颜色和节点编号的映射关系,以便在 dfs 函数中快速查找当前路径上是否出现过相同颜色的节点。
  • 可以使用并查集来优化树的构建过程,将时间复杂度降低到 O(N)。

总结:

本文介绍了树上好点问题的求解方法,并给出了 C++ 代码实现。代码中包含了详细的注释,帮助读者理解代码逻辑。同时,还提供了一些代码优化建议,帮助读者进一步提高代码性能。希望本文能帮助读者更好地理解和解决树上好点问题。

树上好点问题 - C++ 代码实现与优化

原文地址: https://www.cveoy.top/t/topic/b8iw 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录