1 条题解

  • 0
    @ 2026-2-18 15:47:09
    #include<bits/stdc++.h>
    using namespace std;
    
    // [1] 全局常量:最大城镇数量限制,适配题目n<1000的范围
    const int MAXN = 1010;
    // [2] 全局数组:并查集父节点数组,存储每个城镇的父节点编号
    int fa[MAXN];
    // [3] 全局数组:并查集深度数组,用于按秩合并优化,避免树结构退化
    int dep[MAXN];
    
    // [16] 跳转至find函数:带路径压缩,查找节点x所在连通分量的根节点
    int find(int x)
    {
        // [17] 函数参数x:待查找根节点的城镇编号
        if(x != fa[x])
        {
            fa[x] = find(fa[x]); // [18] 路径压缩:直接将当前节点指向根节点,大幅优化后续查询效率
        }
        return fa[x]; // [19] 返回找到的根节点,用于判断两个节点是否属于同一连通分量
    }
    // [20] find函数注释完成,返回unite函数继续注释
    
    // [13] 跳转至unite函数:按秩合并x和y所在的两个城镇连通集合
    void unite(int x, int y)
    {
        // [14] 函数参数x、y:待合并的两个城镇编号
        // [15] 调用find函数查找两个城镇的根节点,跳转至该函数完成注释
        x = find(x);
        y = find(y);
        
        if(x == y) return; // [21] 回到unite函数,两城镇已属于同一连通分量,无需重复合并
        
        // [22] 按秩合并逻辑:将深度更小的树合并到深度更大的树下,保持树结构平衡,优化查询效率
        if(dep[x] > dep[y])
        {
            fa[y] = x;
        }
        else if(dep[x] < dep[y])
        {
            fa[x] = y;
        }
        else
        {
            fa[y] = x;
            dep[x]++; // 两棵树深度相同时,合并后根节点的深度+1
        }
    }
    // [23] unite函数注释完成,返回主函数继续注释
    
    
    // [4] 主函数:程序运行入口
    int main()
    {
        int n, m;
        // [5] 循环处理多组测试数据,当n=0时结束输入
        while(cin >> n && n != 0)
        {
            cin >> m; // [6] 读入当前组的道路总数m
            
            // [7] 循环初始化并查集,为每个城镇初始化连通状态
            for(int i = 1; i <= n; i++)
            {
                fa[i] = i; // [8] 每个城镇初始独立为一个连通分量,父节点设为自身
                dep[i] = 1; // [9] 每个连通分量的初始树深度设为1
            }
            
            // [10] 循环处理所有m条现有道路,合并对应城镇的连通集合
            for(int i = 1; i <= m; i++)
            {
                int a, b;
                cin >> a >> b; // [11] 读入当前道路连接的两个城镇编号
                // [12] 调用unite函数合并两个城镇所在的连通集合,跳转至该函数完成注释
                unite(a, b);
            }
            
            // [23] 回到主函数,所有道路处理完成
            int blockCnt = 0; // [24] 统计变量:记录当前的连通分量总数
            // [25] 循环统计所有城镇的连通分量数量
            for(int i = 1; i <= n; i++)
            {
                // [26] 调用已注释的find函数,判断当前节点是否为连通分量的根节点
                if(find(i) == i)
                {
                    blockCnt++; // [27] 根节点代表一个独立的连通分量,计数+1
                }
            }
            
            // [28] k个连通分量需要k-1条道路即可全部连通,输出最少需要新建的道路数
            cout << blockCnt - 1 << endl;
        }
        return 0;
    }
    
    • 1

    信息

    ID
    1365
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者