题目链接
题意
给定无向图,求完全连通分量
连通分量就是一个连通块的意思
完全连通分量:就是一个连通块中 ,所有点之间都两两有边相连
思路
一个完全联通分量有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-basediota(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;}
};
不能直接用阶乘算,分分钟溢出,我用了递推约分