无向图三/四元环计数小记

三元环计数

先把无向图里的点按度数定序(如果度数相等可以按照编号比较),把每条无向边变为由序更小的点连向序更大的点。

这样做的好处在于,建出的新图是一张 DAG 且每个点的出度是 \(O(\sqrt m)\) 级别的,我们可以方便地枚举。具体地,我们枚举每个三元环中度数最小的那个点,然后接着枚举它的所有出边以及出边的出边,在枚举的过程中更新答案。代码如下:

//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。不同的是为了保证复杂度和正确性,我们在枚举时要先枚举与一个点相连的所有无向边,然后再枚举这些无向边连出的有向边。

原文链接: https://www.cnblogs.com/vectorwyx/p/15784671.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    无向图三/四元环计数小记

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/184632

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 上午10:46
下一篇 2023年2月12日 上午10:46

相关推荐