• 无向图三元环计数(根号算法)


    题目描述

             给定一个 n n n 个点, m m m 条边的简单无向图,求其三元环个数。 1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 1 \leq n \leq 10^5,1 \leq m \leq 2 \times 10^5 1n1051m2×105。 保证图没有 重边自环。但是不保证图联通。

    分析:

    暴力:

             我们考虑暴力该怎么做。注意到边数没有达到 n 2 n^2 n2 级别,而是跟 n n n 同阶,我们考虑枚举边。
             我们枚举一条边,设这条边连接了两个点 u u u v v v。那么我们再枚举一个点 k k k O ( 1 ) O(1) O(1) 的去判断是否存在边 ( u , k ) (u, k) (u,k) ( v , k ) (v, k) (v,k)。时间复杂度 O ( m n ) O(mn) O(mn)
             但是这样做好像会有点浪费,因为如果 k k k 至少和其中任何一个点连接才有枚举的价值。我们可以考虑枚举 u u u 或者 v v v 的所有连边,不妨枚举 u u u 的所有连边,如果某一条连边所连接的点是 k k k,那么我们再 O ( 1 ) O(1) O(1) 的判断是否有 ( k , v ) (k, v) (k,v) 这条边。 时间复杂度是 O ( m 2 ) O(m^2) O(m2)
             我们接着考虑,如果我们每次枚举点 u u u u , v u,v u,v 两个点中度数较小的那个,会不会能够很大的提高效率呢? 如果 u u u u , v u,v u,v 中度数较小的那个,设 u u u 的度数为 d e g u deg_u degu
             如果 d e g u ≤ m deg_u \leq \sqrt{m} degum ,那么很显然 m × m m \times \sqrt{m} m×m 不会超时。
             如果 d e g u ≥ m deg_u \geq \sqrt{m} degum 那么就意味着 d e g v ≥ m deg_v \geq \sqrt{m} degvm 。我们考虑到所有点的度数之和为 2 m 2m 2m,所以度数超过 m \sqrt{m} m 的点的数量小于 m \sqrt{m} m 个。首先因为没有重边,所以 n 2 ≥ m n^2 \geq m n2m。所以 n ≥ m n \geq \sqrt{m} nm 。并且每个点的度数小于等于 n n n。 我们想让所有点的度数都平均的尽可能大,考虑极端数据就是 m \sqrt{m} m 个点,每一个点的度数都是 m + 1 \sqrt{m} + 1 m +1 的完全图,我们考虑在这种情况下复杂度是 O ( m m ) O(m \sqrt{m}) O(mm ) 的也不会超时。至于那种想让某几个点度数很大,其他点度数很小的菊花图,我们发现也只会在枚举个别边的时候复杂度会比较高,其他情况还是很小的。所以也超时不了。
             这样做好像可行了,应该能拿到不少的分了。

    正解:

             我们把无向图变成 有向图,给每个边加一个方向
             加方向的规则是,对于一条边 ( u , v ) (u,v) (u,v) 而言,我们让其由度数小的点指向度数大的点。如果度数一样,就让编号小的点指向编号大的点。
             具体来讲, u → v u \to v uv 的条件是 d e g u < d e g v deg_u < deg_v degu<degv 或者 d e g u = d e g v deg_u = deg_v degu=degv 并且 u < v u < v u<v
             我们发现,在这样的条件下,形成的有向图 一定无环,可以把连边规则看作是优先级,那么有向边就是某一组优先关系,所以一定不会存在环。 进一步,我们发现,原图中的所有环一定等价于所有的形如 u → v u \to v uv u → k u \to k uk v → k v \to k vk 的三元关系。我们只要找出来所有这样的三元关系就好了。
             方法是我们枚举一个点 u u u 的所有出边,并且把所有出点 v v v 打上时间戳为 u u u 的标记。然后枚举所有 v v v 的出边,如果有一个出点 k k k 的时间戳是 u u u,那么让答案加1。这样做等价于 以每一个点作为环中优先级最低的点,找出所有这样的环的数量。所以是不重不漏的。

             我们来分析复杂度。
             首先就是任意一个点的出度不会超过 m \sqrt{m} m 。因为如果一个点在原图中的度数小于 m \sqrt{m} m ,那么在有向图上它都出度不会超过原图上的度数。所以小于 m \sqrt{m} m
             如果一个点在原图中的度数大于 m \sqrt{m} m ,但是连边的条件是度数小的点朝度数大的点连边,因为总边数为 m m m,所以度数大于 m \sqrt{m} m 的点不会超过 m \sqrt{m} m 个,因此这个点的出度也不会超过 m \sqrt{m} m
             每一个点对复杂度的贡献是 I n i × O u t i In_{i} \times Out_i Ini×Outi I n i In_i Ini i i i 号点的入度, O u t i Out_i Outi i i i 号点的出度。因为 O u t i Out_i Outi m \sqrt{m} m 量级,而 ∑ i = 1 n I n i = m \sum_{i = 1}^{n} In_i = m i=1nIni=m。所以总复杂度是 O ( m × m ) O(m \times \sqrt{m}) O(m×m )

    CODE:

    #include
    #define N 100100
    #define M 200100
    #define pb push_back
    #define LL long long
    using namespace std;
    int n, m, u[M], v[M], deg[N], tim[N];
    vector< int > E[N];
    LL res;
    int main(){
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++){
    		scanf("%d%d", &u[i], &v[i]);
    		deg[u[i]]++; deg[v[i]]++;
    	}
    	for(int i = 1; i <= m; i++){
    		if(deg[u[i]] != deg[v[i]]){
    			if(deg[v[i]] > deg[u[i]]) swap(u[i], v[i]);
    			E[v[i]].pb(u[i]);//每一个里面放比它度数大的 
    		}
    		else{
    			if(u[i] > v[i]) swap(u[i], v[i]);
    			E[u[i]].pb(v[i]);
    		}
    	}
    	for(int u = 1; u <= n; u++){
    		for(auto v : E[u]){// 扫描出边, 复杂度O(m) 
    			tim[v] = u;
    		}
    		for(auto v : E[u]){
    			for(auto x : E[v]){//扫描出边的出边,每一条边会被扫到一次,一个边贡献√m的复杂度,所以总复杂度是O(m√m) 的 
    				if(tim[x] == u) res++; 
    			}
    		}
    	}
    	printf("%lld\n", res);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
  • 相关阅读:
    10-JavaSE基础巩固练习:综合练习、二维数组
    Latex | 公式编辑
    什么是智能档案柜?如何使用智能档案柜?
    肠道微生物可改善围手术期和术后康复效果
    monorepo 下的 package tsc 构建
    CSS选择器和样式[补充]
    介绍一下标准的 CSS 的盒子模型?低版本 IE 的盒子模型有什么不同的?
    CF1490F Equalize the Array
    关于模糊理论及简单应用
    huggingface笔记: accelerate estimate-memory 命令
  • 原文地址:https://blog.csdn.net/weixin_55851276/article/details/134034074