[leetcode]2685. 统计完全连通分量的数量

题目链接

题意

给定无向图,求完全连通分量
连通分量就是一个连通块的意思
完全连通分量:就是一个连通块中 ,所有点之间都两两有边相连

思路

一个完全联通分量有n个点 那么应该有 C n 2 C_n^2 Cn2条边
并查集维护连通块
检查每个联通分量是否有 C n 2 C_n^2 Cn2条边
如果有就ans++

Code

#define pii pair<int,int>
#define ar2 array<int,2>
#define ar3 array<int,3>
#define ar4 array<int,4>
#define endl '\n'
void cmax(int &a,int b){a=max(a,b);};
void cmin(int &a,int b){a=min(a,b);};
const int N=1e5+10,MOD=1e9+7,INF=0x3f3f3f3f;const long long LINF=LLONG_MAX;const double eps=1e-6;
int a[N];

class UnionFind{
private:
    vector<int>p,s,ecnt;//ecnt[i]表示以find(i)为根的连通块的边数
    unordered_set<int>roots;
public:
    UnionFind(int n): p(n+1),s(n+1,1),ecnt(n+1,0){//多开一个空间 同时适用于0-based&1-based
        iota(p.begin(),p.end(),0);
        for(int i=0;i<n;i++){//如果1-based就改成i->[1,n]
        	roots.insert(i);
        }
    }

    int find(int x){
        if(p[x]!=x) p[x]=find(p[x]);
        return p[x];
    }

    void merge(int u,int v){
        int uu=find(u),vv=find(v);
        if(uu!=vv){
            if(s[uu]>s[vv]){
                p[vv]=uu;
                s[uu]+=s[vv];
                ecnt[uu]+=ecnt[vv]+1;
                roots.erase(vv);
            }else {
                p[uu]=vv;
                s[vv]+=s[uu];
                ecnt[vv]+=ecnt[uu]+1;
                roots.erase(uu);
            }
        }else{
			ecnt[uu]++;//已经联通了也要加边数
		}
    }
    
	bool is_connected(int u,int v){
        return find(u)==find(v);
    }
    
    int size(int x){
        return s[find(x)];
    }	

	int get_ecnt(int x){
		return ecnt[find(x)];
	}    

    vector<int>get_roots(){
		return vector<int>(roots.begin(),roots.end());
	}
	
	int get_cnt(){
		return roots.size();
	}
};

using ll = long long;

ll c[60][60];
void init(){
    for(int i=0;i<60;i++){
        c[i][0]=c[i][i]=1;
        for(int j=1;j<i;j++){
            c[i][j]=c[i-1][j-1]+c[i-1][j];
        }
    }
}

class Solution {
public:
    int countCompleteComponents(int n, vector<vector<int>>& edges) {
        UnionFind uf(n);
        for(auto e:edges){
            int u=e[0],v=e[1];
            uf.merge(u,v);
        }
        init();
        auto v=uf.get_roots();
        int ans=0;

        for(int i:v){
            if(c[uf.size(i)][2]==uf.get_ecnt(i)) ans++;
        }
        return ans;

    }
};

不能直接用阶乘算,分分钟溢出,我用了递推约分

你可能感兴趣的:(leetcode,算法,职场和发展)