题目
用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。
网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。
给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。
示例 1:
输入:n = 4, connections = [[0,1],[0,2],[1,2]] 输出:1 解释:拔下计算机 1 和 2 之间的线缆,并将它插到计算机 1 和 3 上。
示例 2:
输入:n = 6, connections = [[0,1],[0,2],[0,3],[1,2],[1,3]] 输出:2
示例 3:
输入:n = 6, connections = [[0,1],[0,2],[0,3],[1,2]] 输出:-1 解释:线缆数量不足。
示例 4:
输入:n = 5, connections = [[0,1],[0,2],[3,4],[2,3]] 输出:0
解题
方法一:并查集
- 比如有n台电脑,如果连接线数小于n-1,那么一定是没法成功的。
如果连线数大于等于n-1,那么一定可以通过一定的修改,以此来修改成功 - 由于连接数大于等于n-1则一定可以修改成功,那么可以使用并查集,得到最后剩下的集合个数m,那么最后需要修改的,就需要m-1根即可。
class UnionFind{ private: vector<int> parent; int setNum; public: UnionFind(int n){ parent.resize(n); iota(parent.begin(),parent.end(),0); setNum=n; } int find(int index){ if(parent[index]==index) return index; return parent[index]=find(parent[index]); } void unite(int index1,int index2){ int p1=find(index1); int p2=find(index2); if(p1!=p2){ parent[p1]=p2; setNum--; } } int getSetNum(){ return setNum; } }; class Solution { public: int makeConnected(int n, vector<vector<int>>& connections) { if(connections.size()<n-1) return -1;//n台电脑,至少需要n-1条线,否则不可能成功 UnionFind uf(n); for(vector<int>& conn:connections){ uf.unite(conn[0],conn[1]); } return uf.getSetNum()-1;//如果还剩下m个集合,那么修改m-1条线 } };