[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;
}
};
不能直接用阶乘算,分分钟溢出,我用了递推约分