1319. 连通网络的操作次数——并查集

1319. 连通网络的操作次数

用以太网线缆将 n 台计算机连接成一个网络,计算机的编号从 0 到 n-1。线缆用 connections 表示,其中 connections[i] = [a, b] 连接了计算机 a 和 b。

网络中的任何一台计算机都可以通过网络直接或者间接访问同一个网络中其他任意一台计算机。

给你这个计算机网络的初始布线 connections,你可以拔开任意两台直连计算机之间的线缆,并用它连接一对未直连的计算机。请你计算并返回使所有计算机都连通所需的最少操作次数。如果不可能,则返回 -1 。 


我的第一反应是先将所有已知边连接起来,然后对每一条边检查是否为冗余边,是的话就使用它连接后面未连接的边。

class UF{
    vector<int> parent;
    int tmpconnect=1;
public:
    UF(int n){
        parent=vector<int>(n,0);
        for(int i=1;i<n;i++)parent[i]=i;
    }
    int find(int x){
        if(parent[x]!=x) parent[x]=find(parent[x]);
        return parent[x];
    }
    void un(int x, int y){
        if(find(x)==find(y))return;
        parent[find(y)]=parent[x];
    }
    bool rest(int x, int y){
        int a=find(x),b=find(y);
        if(a==b&&a!=x&&b!=y)return true;
        return false;
    }
    int connect(int n){
        for(int i=tmpconnect;i<n;i++){
            if(find(i)!=find(i-1)){
                tmpconnect=i;
                return i;
            }
        }
        return -1;
    }                   //找出不连通的点
    void show(int n){
        for(int i=0;i<n;i++)cout<<parent[i]<<" ";
        cout<<endl;
    }
};

class Solution {
public:
    int makeConnected(int n, vector<vector<int>>& connections) {
        UF Union(n);
        for(int i=0;i<connections.size();i++){
            Union.un(connections[i][0],connections[i][1]);
        }
        int ans=0;
        for(int i=0;i<connections.size();i++){
            if(Union.rest(connections[i][0],connections[i][1])){  //是冗余边
                int t=Union.connect(n);
                if(t==-1)return ans;        //全部连通
                else{
                    Union.un(t-1,t);        //合并不连通的点
                    ans++;                  //使用边数+1
                }
            }
        }
        if(Union.connect(n)==-1)return ans;
        return -1;
    }
};

但其实没有必要这样做, 因为我们只需要知道一个移动次数。一个n个结点的图至少需要n-1条边才可以连通,并且最小移动次数=连通分量数-1

class Solution {
    vector<int> parent;
    vector<int> sz;
public:
    int find(int x){
        if(parent[x]!=x) parent[x]=find(parent[x]);
        return parent[x];
    }
    void un(int x, int y){
        if(sz[x]>=sz[y]){
            parent[find(y)]=find(x);
            sz[x]+=sz[y];
        }
        else{
            parent[find(x)]=find(y);
            sz[y]+=sz[x];
        }
    }
    // void un(int x, int y){
    //     parent[find(y)]=find(x);
    // }
    int makeConnected(int n, vector<vector<int>>& connections) {
        if(connections.size()<n-1)return -1;
        parent=vector<int>(n,0);
        for(int i=1;i<n;i++)parent[i]=i;
        sz=vector<int>(n,1);
        int part=n;
        for(auto& x:connections){
            if(find(x[0])!=find(x[1])){
                un(x[0],x[1]);
                part--;
            }
        }
        return part-1;
    }
};

事实证明这俩差不多快。。。

原文地址:https://www.cnblogs.com/Dancing-Fairy/p/12942427.html