Description
给定简单无向图 \(G=(V,E)\),求其三元环个数,其中 \(\lvert V\rvert\leq10^5,\lvert E\rvert\leq 2\times 10^5\)。
Solution
考虑给每一个边定一个方向。具体地,对于原图的一条边 \(E=(u,v)\),有
- 若 \(\deg_u>\deg_v\) 或 \(\text{deg}_u=\text{deg}_v\land u<v\),则 \(u\to v\)
- 否则 \(v\to u\)
给边定完方向后,原图变成了一个有向无环图 。
注意到原图中的三元环一定与对应有向图中所有形如 \(E'=(u\to v,u\to w,v\to w)\) 的子图一一对应。
只需要枚举 \(u\) 的出边,再枚举 \(v\) 的出边,然后检查 \(w\) 是否为 \(u\) 指向的点即可。时间复杂度为 \(\mathcal O(m\sqrt m)\)。
- 为什么时间复杂度为 \(O(m\sqrt m)\)?
首先在在枚举 \(u\) 的出边时打上 \(u\) 的时间戳,这样在枚举 \(v\) 的出边时可以 \(O(1)\) 判断。
那么考虑每一条边 \(u\to v\) 的贡献为 \(out_v\),所以总复杂度为 \(\sum\limits_{i=1}^{m} out_{v_i}\),其中 \(v_i\) 是第 \(i\) 条边指向的点, \(out_v\) 是点 \(v\) 的出度。
对于每一个点 \(v\) 分情况讨论。
- 当在原图上 \(\deg_v\leq\sqrt m\) 时,由于新图每个节点的出度不可能大于原图的度数,所以 \(out_v=O(\sqrt m)\)。
- 当在原图上 \(\deg_v>\sqrt m\) 时,注意到它只能向原图中度数不小于它的点连边,又因为原图中所有的点的度数和为 \(O(m)\),所以原图中 \(\deg>\sqrt m\) 的点只有 \(O(\sqrt m)\) 个。因此 \(v\) 的出边只有 \(O(\sqrt m)\) 条,即 \(out_v=O(\sqrt m)\)。
综上所有点的度数都为 \(O(\sqrt m)\),总复杂度就为 \(O(m\sqrt m)\)。
Code
const int N=1e5+5;
int n,m,deg[N],vis[N],ans;
struct E{int u,v;}e[N*3];
vector<int>G[N];
signed main(){
n=read();m=read();
for(int i=1;i<=m;i++){
e[i]=(E){read(),read()};
deg[e[i].u]++;deg[e[i].v]++;
}
for(int i=1;i<=m;i++){
int u=e[i].u,v=e[i].v;
if(deg[u]<deg[v] or (deg[u]==deg[v] and u>v))
swap(u,v);
G[u].eb(v);
}
for(int u=1;u<=n;u++){
for(auto v:G[u])
vis[v]=u;
for(auto v:G[u])
for(auto w:G[v])
if(vis[w]==u)
ans++;
}
write(ans);
return 0;
}
标签:原图,int,sqrt,计数,无向,出边,三元,out,deg
From: https://www.cnblogs.com/QcpyWcpyQ/p/18286457