Liuchang0911 2025-07-26 21:03 采纳率: 0%
浏览 14

3682图的连通分量

AcWing3682 图的连通分量**
https://www.acwing.com/problem/content/description/3685/
给定 m个不同的整数 a1,a2,…,am,每个数都处于 [0,2n−1]的范围内。

一个图按照如下约束建立:

如果整数 X 和 Y满足 X&Y=0(&是按位与运算),则 X和 Y 由一条无向边连接。

请计算,图中连通分量的数量。

输入格式
输入包含不超过 10组测试数据。

每组数据第一行包含两个整数 n,m。

第二行包含 m个整数 a1,a2,…,am。

输出格式
每组数据输出一行结果,表示连通分量的个数。

数据范围
0≤n≤22,
1≤m≤2n,
0≤ai<2n

输入样例:
2 3
1 2 3
5 5
5 19 10 20 12
5 6
5 19 10 20 12 0

输出样例:
2
2
1

谁能解释一下呀,什么是连通分量呀,太难为我初中生了

  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-07-26 21:22
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    连通分量(Connected Component) 是图论中的一个基本概念。简单来说,在一个无向图中,如果两个顶点之间可以通过一系列边连接起来,那么这两个顶点就属于同一个连通分量

    举个例子:

    • 如果你有一张图,其中有些点互相连着,而另一些点不连着,那么每个“独立的块”就是一个连通分量
    • 例如,如果图中有3个互不相连的点,那么就有3个连通分量;如果有两个点相连,另一个点不连,那么就是2个连通分量

    题目解析

    题目给出的是一个特殊的图结构,其构造规则如下:

    如果两个整数 X 和 Y 满足 X & Y = 0(按位与),则它们之间有一条无向边

    也就是说,只要两个数在二进制下没有任何一位同时为1,它们之间就会有边。

    我们的任务是:给定一组数,计算这个图中有多少个连通分量


    解题思路

    1. 理解图的构造方式

    我们不是直接构造整个图,而是通过判断两个数是否满足 X & Y == 0 来判断是否有边。

    但是,如果我们直接对所有数两两比较,时间复杂度会很高(比如 m=2^22 时,m^2 就是 2^44,显然不行)。

    所以我们要找一个更高效的方式。


    2. 观察性质:连通分量与二进制位有关

    注意到:两个数 X 和 Y 能连通的条件是 它们的二进制表示没有重叠的1

    我们可以把这个问题转化为一个集合问题:找出所有可以相互连接的数,形成一个连通分量。


    3. 使用并查集(Union-Find)算法

    我们可以使用并查集来处理这个问题:

    • 初始化每个数为一个独立的集合。
    • 对于每一对数 (X, Y),如果 X & Y == 0,就把它们合并到一个集合中。
    • 最后统计有多少个不同的集合,就是连通分量的数量。

    4. 优化方法(关键)

    由于 n 的范围是 [0, 22],即最大是 2^22 ≈ 4 million。对于 m ≤ 2^n,我们可以考虑以下优化:

    • 将所有的数转换成二进制形式,然后根据它们的二进制位来判断是否可以连通。
    • 但这样还是需要两两比较,时间复杂度太高。

    5. 更高效的观察

    我们可以从位的角度来看:

    • 一个数 X 可以和那些二进制位与 X 的二进制位没有交集的数相连。
    • 所以,我们可以将数按照它们的二进制位进行分类,看看哪些数能组成一个连通分量。

    举个例子帮助理解

    输入样例:

    2 3
    1 2 3
    

    这表示 n=2,也就是所有数都在 [0, 3] 范围内,共有 3 个数:1, 2, 3。

    我们来看看它们之间的关系:

    • 1 (01) 和 2 (10):1&2=0 → 有边
    • 1 (01) 和 3 (11):1&3=1 → 没有边
    • 2 (10) 和 3 (11):2&3=2 → 没有边

    所以图中只有 1 和 2 相连,3 单独存在。

    因此,连通分量数量是 2


    正确的解法步骤(详细)

    ✅ 步骤一:读取输入

    • 读取 n 和 m。
    • 读取 m 个整数 a1, a2, ..., am。

    ✅ 步骤二:初始化并查集

    • 使用并查集结构,初始时每个数是一个独立的集合。

    ✅ 步骤三:遍历所有数对

    • 对于每对 i < j:
      • 如果 a[i] & a[j] == 0,说明它们之间有边,将它们合并。

    ✅ 步骤四:统计连通分量数量

    • 遍历所有数,统计有多少个不同的根节点(即不同的集合)。

    示例代码(Python)

    def find(parent, x):
        if parent[x] != x:
            parent[x] = find(parent, parent[x])
        return parent[x]
    
    def union(parent, rank, x, y):
        root_x = find(parent, x)
        root_y = find(parent, y)
        if root_x != root_y:
            if rank[root_x] > rank[root_y]:
                parent[root_y] = root_x
            else:
                parent[root_x] = root_y
                if rank[root_x] == rank[root_y]:
                    rank[root_y] += 1
    
    def count_components(n, m, nums):
        parent = {}
        rank = {}
    
        for num in nums:
            parent[num] = num
            rank[num] = 0
    
        for i in range(m):
            for j in range(i + 1, m):
                if (nums[i] & nums[j]) == 0:
                    union(parent, rank, nums[i], nums[j])
    
        roots = set()
        for num in nums:
            roots.add(find(parent, num))
    
        return len(roots)
    
    # 测试样例
    import sys
    input = sys.stdin.read
    data = input().split()
    
    idx = 0
    while idx < len(data):
        n = int(data[idx])
        m = int(data[idx + 1])
        idx += 2
        nums = list(map(int, data[idx:idx + m]))
        idx += m
        print(count_components(n, m, nums))
    

    重点总结

    • 连通分量:图中互相可达的点构成一个连通分量。
    • 关键条件:X & Y == 0 表示 X 和 Y 可以连通。
    • 解决方法:使用并查集来合并符合条件的点。
    • 时间复杂度:O(m²)(在 m 较小的情况下可行)。
    • 优化建议:对于大范围数据,可以尝试基于二进制位的优化。

    如果你是初中生,没关系!这个题目虽然看起来难,但理解了基本概念之后,就可以一步步解决啦 😊

    评论

报告相同问题?

问题事件

  • 创建了问题 7月26日