1、描述
用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-operations-to-make-network-connected
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2、关键字
联通,最小,连通分量
3 、思路
想到无向图中的连通分量,连通分量-1,就是最少的需要的网线数,图种求连通分量的个数,就是用并查集,
并查集参照
4、notes
==,不要写成=,不然肯定又是时间超限,因为一直在赋值,
iota(pre.begin(),pre.end(),0);
用顺序递增的值赋值指定范围内的元素
5、复杂度
时间:O(Nlong(N)+M),只使用了路径压缩,没有用按秩合并(小连通图合并成大连通图),就是这个时间复杂度
空间:O(N)
6、code
class Solution {
private:
vector<int>pre;
public:
int findset(int root){ // 找掌门人
int son,tem;//为了路径压缩,保存下标的变量
son=root; // 记录当前要查的下标
//if(root=pre[root]) //这一句判断写成复制,就一直时间超限!!!!
if(root==pre[root])//自己就是掌门人
return root;
while(root!=pre[root]) //一直找到掌门人
{
root=pre[root];
}
while(son!=root) // 路径压缩
{
tem=pre[son];//记录下标为son==5的时候的值tem==4
pre[son]=root; // 把当前下标5的 值 换成掌门人 0
son=tem; // 更新下标,一路直接都换成掌门人
}
return root;
}
int makeConnected(int n, vector<vector<int>>& connections) {
if(connections.size()<n-1) // 特判
return -1;
pre.resize(n);
//iota(pre.begin(),pre.end(),0); // 这一句也行
for(int i=0;i<n;i++) // 初始化,大家都是自己的掌门人
{
pre[i]=i;
}
int party=n; // n个门派
for(auto && tem:connections) // 合并,
{
int p=findset(tem[0]);
int q=findset(tem[1]);
if(p!=q) // 第一次遍历的时候,自己是自己的掌门人,合并掌门人,门派-1
{
pre[q]=p;
--party;
}
} //最后的party就是最后的门派数目
return party-1;
}
};