无向图三元环计数
无向图三元环计数
三元环
无向图
solution
考虑给边一个方向,重新建图,规则如下:
- 如果一条边两个端点的度数不一样,则由度数较小的点连向度数较大的点
(ps:大向小连边好像也可过,但是复杂度不会证) - 如果度数一样,则由编号较小的点连向编号较大的点(或其他规则)
可以证明新建的图是有向无环图(DAG)
原图中的三元环一定与对应有向图中所有形如
只需要枚举
复杂度证明
- 当
时,由于新图中 的出度不大于原图中 的度数,所以 的出度是 的 - 当
时,由于它只能向原图中度数大于等于它的点连边,又因为原图中所有的点的度数和是 的,所以原图中度数大于 的点是 的,所以 的出度是 的
il int calc(){
ri int as=0;
for(ri int i=1;i<=m;++i){
if(deg[u[i]]<deg[v[i]]) e[u[i]].push_back(v[i]);
else if(deg[u[i]]>deg[v[i]]) e[v[i]].push_back(u[i]);
else{
if(u[i]<v[i]) e[u[i]].push_back(v[i]);
else e[v[i]].push_back(u[i]);
}
}
for(ri int i=1;i<=n;++i){
for(ri int vi:e[i]) t[vi]=i;
for(ri int vi:e[i]){
for(ri int w:e[vi]){
if(t[w]==i) as++;
}
}
}
return as;
}
code
#include<bits/stdc++.h>
#define il inline
#define ri register
#define cs const
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10+48),void();
}
} using namespace Q;
cs int N=1e5+1,M=2e5+1;
int n,m,u[M],v[M],deg[N],t[N];
vector<int> e[N];
il int calc(){
ri int as=0;
for(ri int i=1;i<=m;++i){
if(deg[u[i]]<deg[v[i]]) e[u[i]].push_back(v[i]);
else if(deg[u[i]]>deg[v[i]]) e[v[i]].push_back(u[i]);
else{
if(u[i]<v[i]) e[u[i]].push_back(v[i]);
else e[v[i]].push_back(u[i]);
}
}
for(ri int i=1;i<=n;++i){
for(ri int vi:e[i]) t[vi]=i;
for(ri int vi:e[i]){
for(ri int w:e[vi]){
if(t[w]==i) as++;
}
}
}
return as;
}
signed main(){
n=rd(),m=rd();
for(ri int i=1;i<=m;++i){
u[i]=rd(),v[i]=rd();
deg[u[i]]++,deg[v[i]]++;
}
wt(calc());
return 0;
}
也可以枚举边
il int calc(){
ri int s=0;
for(ri int i=1,u,v;i<=m;++i){
u=o[i].u,v=o[i].v;
if(deg[u]<deg[v]) e[u].push_back(v);
else if(deg[u]>deg[v]) e[v].push_back(u);
else{
if(u<v) e[u].push_back(v);
else e[v].push_back(u);
}
}
for(ri int i=1,u,v;i<=m;++i){
u=o[i].u,v=o[i].v;
for(ri int q:e[u]) vs[q]=i;
for(ri int q:e[v]) if(vs[q]==i) s++;
}
return s;
}
code
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define int long long
using namespace std;
namespace Q{
il int rd(){
ri int x=0;ri bool f=0;ri char c=getchar();
while(!isdigit(c)) f|=(c==45),c=getchar();
while(isdigit(c)) x=x*10+(c^48),c=getchar();
return f?-x:x;
}
il void wt(int x){
if(x<0) x=-x,putchar(45);
if(x>=10) wt(x/10);
return putchar(x%10+48),void();
}
} using namespace Q;
cs int N=1e5+1;
int n,m,as,deg[N],vs[N];
struct qwq{
int u,v;
}o[N<<1];
vector<int> e[N];
il int calc(){
ri int s=0;
for(ri int i=1,u,v;i<=m;++i){
u=o[i].u,v=o[i].v;
if(deg[u]<deg[v]) e[u].push_back(v);
else if(deg[u]>deg[v]) e[v].push_back(u);
else{
if(u<v) e[u].push_back(v);
else e[v].push_back(u);
}
}
for(ri int i=1,u,v;i<=m;++i){
u=o[i].u,v=o[i].v;
for(ri int q:e[u]) vs[q]=i;
for(ri int q:e[v]) if(vs[q]==i) s++;
}
return s;
}
signed main(){
n=rd(),m=rd();
for(ri int i=1;i<=m;++i){
o[i]={rd(),rd()};
deg[o[i].u]++,deg[o[i].v]++;
}
wt(calc());
return 0;
}
I went to the woods because I wanted to live deliberately, I wanted to live deep and suck out all the marrow of life, and not when I had come to die, discover that I had not live.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】