题目描述:
用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
示例:
提示:
- 1 <= n <= 10^5
- 1 <= connections.length <= min(n*(n-1)/2, 10^5)
- connections[i].length == 2
- 0 <= connections[i][0], connections[i][1] < n
- connections[i][0] != connections[i][1]
- 没有重复的连接。
- 两台计算机不会通过多条线缆连接。
解题思路:
这道题又是连通分量问题,我们可以使用并查集来解决。给你n个计算机,我们需要n-1条边才能把所有点连接到一块。所以当connections的长度小于n-1的时候,无法把所有计算机连接到一块,直接返回-1。除了这个情况外,我们求原本连接网络中的连通分量的个数size,然后用size-1,就是这个题目的解。假如我们有M个连通分量,我们向把这M个连通分量连到一块需要M-1条边。
具体代码如下:
public class 连通网络的操作次数 {
public static int makeConnected(int n, int[][] connections) {
int len = connections.length;
if(len<n-1)
{
return -1;
}
UnionFind uFind = new UnionFind(n);
for(int i = 0;i<len;i++)
{
int[] con = connections[i];
uFind.union(con[0], con[1]);
}
return uFind.size-1;
}
// 并查集套路代码
static class UnionFind{
int[] parent;
int size;
int n;
public UnionFind(int n) {
this.n = n;
size = n;
parent = new int[n];
for(int i = 0;i<n;i++)
{
parent[i] = i;
}
}
int find(int x)
{
if(x==parent[x])
return x;
return parent[x] = find(parent[x]);
}
void union(int x,int y)
{
if(find(x)==find(y))
return;
parent[find(x)] = find(parent[y]);
size--;
}
}
// 测试
public static void main(String[] args) {
int n = 4;
int[][] connections= {{0,1},{0,2},{1,2}};
int res = makeConnected(n,connections);
System.out.println(res);
}
}