无向图三/四元环计数小记
三元环计数
先把无向图里的点按度数定序(如果度数相等可以按照编号比较),把每条无向边变为由序更小的点连向序更大的点。
这样做的好处在于,建出的新图是一张 DAG 且每个点的出度是 级别的,我们可以方便地枚举。具体地,我们枚举每个三元环中度数最小的那个点,然后接着枚举它的所有出边以及出边的出边,在枚举的过程中更新答案。代码如下:
//author:望远星
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define sml(x,y) (x=min(x,y))
#define big(x,y) (x=max(x,y))
#define ll long long
#define ull unsigned long long
#define db double
#define fo(i,x,y) for(int i=x;i<=y;++i)
#define go(i,x,y) for(int i=x;i>=y;--i)
using namespace std;
inline int read(){int x=0,fh=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-') fh=-1; ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();} return x*fh;}
inline void out(int *a,int l,int r){fo(i,l,r) cout<<*(a+i)<<' ';puts("");}
const int N=1e5+5;
vector<int> e[N];
pii ed[N<<1];
int n,m,deg[N],vis[N],ti;
signed main(){
cin>>n>>m;
fo(i,1,m){
int x=read(),y=read();
deg[x]++,deg[y]++;
ed[i]=mk(x,y);
}
fo(i,1,m){
if(deg[ed[i].fi]>deg[ed[i].se]||(deg[ed[i].fi]==deg[ed[i].se]&&ed[i].fi>ed[i].se)) swap(ed[i].fi,ed[i].se);
e[ed[i].fi].pb(ed[i].se);
}int ans=0;
fo(i,1,n){
++ti;
for(int j:e[i]) vis[j]=ti;
for(int j:e[i]) for(int k:e[j]) ans+=vis[k]==ti;
}
cout<<ans;
return 0;
}
例题:CF985G,以及自己的题解 https://www.luogu.com.cn/blog/dream-of-Au/solution-cf985g
四元环计数
和三元环计数类似,还是先定序然后建出 DAG。不同的是为了保证复杂度和正确性,我们在枚举时要先枚举与一个点相连的所有无向边,然后再枚举这些无向边连出的有向边。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现