首页 > 其他分享 >三元环

三元环

时间:2023-07-09 15:55:10浏览次数:41  
标签:int 复杂度 sqrt 三元组 三元 outdeg

无向图三元环

给定一张无重边、无自环的无向图

点数为 \(n\) ,边数为 \(m\) ,其中 \(n, m\) 同阶

求有多少个无序三元组 \((i, j, k)\) 满足:

  • 有一条连接 \(i, j\) 的边
  • 有一条连接 \(j, k\) 的边
  • 有一条连接 \(i, j\) 的边

首先考虑暴力,枚举所有三元组判断是否满足条件,时间复杂度 \(O(n^3)\)

考虑更优秀的做法,我们对任何一条边,将其定向为从度数大的点连向度数小的点,若度数相同则从编号小的点连向编号大的点,此时这张图就是一张有向无环图

之后枚举每个点 \(u\) ,将所有 \(u\) 有出边的点都打上 \(u\) 的标记,再枚举所有打上标记的点 \(v\) 的所有有出边的点 \(w\) ,若 \(w\) 有被 \(u\) 标记过,那么 \((u, v, w)\) 就是一个三元环

证明正确性:

  • 定向后的图是有向无环图

    每条边的连边判定点的大小关系具有传递性,即 \(i \to j \to k\) 时 \((i, k)\) 的边只能是 \(i \to k\) ,故定向后的图是有向无环图

  • 每个三元环只会被统计一次

    显然,每个三元环只会在 \(u\) 处被统计一次

时间复杂度为 \(O(m \sqrt{m})\)

对于打标记这个操作,我们会遍历所有点与所有边,时间复杂度为 \(O(n + m)\)

对于访问 \(u, v, w\) 的操作,考虑每条边 \(u \to v\) 对实际按复杂度的贡献为 \(outdeg_v\) ,其中 \(outdeg_v\) 表示 \(v\) 的出度,这样就转化为求 \(\sum outdeg_i\)

不妨分类讨论

  • \(outdeg_v \leq \sqrt{m}\) ,由于 \(u\) 连接 \(v\) ,因此 \(deg_u > deg_v\) ,这样的 \(u\) 的个数是 \(O(n)\) 的,因此时间复杂度为 \(O(n \sqrt{m})\)
  • \(outdeg_v > \sqrt{m}\) ,那么由于 \(u\) 连接 \(v\) ,因此 \(deg_u > deg_v > outdeg_v > \sqrt{m}\) ,这样的 \(u\) 的个数是 \(O(\sqrt{m})\) 的,因此时间复杂度为 \(O(m \sqrt{m})\)

故总时间复杂度为 \(O(n + m + n \sqrt{m} + m \sqrt{m}) = O(m \sqrt{m})\)

应用

P1989 无向图三元环计数

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7, M = 2e5 + 7;

struct Edge {
	int u, v;
} E[M];

vector<int> e[N];

int deg[N], tag[N];

int n, m, ans;

signed main() {
	scanf("%d%d", &n, &m);
	
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d", &E[i].u, &E[i].v);
		++deg[E[i].u], ++deg[E[i].v];
	}
	
	for (int i = 1, u, v; i <= m; ++i) {
		u = E[i].u, v = E[i].v;
		
		if (deg[u] < deg[v] || (deg[u] == deg[v] && u > v))
			swap(u, v);
		
		e[u].push_back(v);
	}
	
	for (int i = 1; i <= n; ++i) {
		for (int j : e[i])
			tag[j] = i;
		
		for (int j : e[i])
			for (int k : e[j])
				if (tag[k] == i)
					++ans;
	}
	
	printf("%d", ans);
	return 0;
}

P6815 [PA2009]Cakes

竞赛图三元环

定义

每两个点都有连边的有向图称为竞赛图

性质

对于一个竞赛图,其要么是一个拓扑图,要么存在一个三元环(即若竞赛图中存在环,则一定是三元环)

证明

考虑反证法,若存在环且不是三元环,那么会有在大环上的三元组 \((i, j, k)\) 且存在边 \(i \to j, j \to k\) ,若 \(i, k\) 的连边方向为 \(k \to i\) ,则其就是三元环;若为 \(i \to k\) 那么会得到一个把 \(j\) 排除在外的小一点的环,递归证明最后也是一个三元环。故竞赛图中存在环,则一定是三元环

线性求法

直接选出三个点,考虑容斥掉不是三元环的情况,当且仅当这个三元组有一点出度为 \(2\) ,这样的三元组不可能构成环。答案即为

\[\dbinom{n}{3} - \sum \dbinom{outdeg_i}{2} \]

标签:int,复杂度,sqrt,三元组,三元,outdeg
From: https://www.cnblogs.com/wshcl/p/17538846.html

相关文章

  • 力扣 334. 递增的三元子序列
    题目:给你一个整数数组 nums,判断这个数组中是否存在长度为3的递增子序列。如果存在这样的三元组下标(i,j,k) 且满足i<j<k,使得 nums[i]<nums[j]<nums[k],返回true;否则,返回false。 示例1:输入:nums=[1,2,3,4,5]输出:true解释:任何i<j<k的三元组都......
  • [典·三元组]
    题目:MEX 来源:AtCoderBeginnerContest308根据例1可以先进行判断,如果根据E的不同情况进行统计的话方便入手1.从左到右统计M的{0,1,2}的情况2.从右到左统计X的{0,1,2}的情况3.判断当前s[i]为‘E’的情况下,并且对应的a[i]={0,1,2}三种情况相乘的个数(乘的是三元组的没出现的最......
  • Vue全局过滤器的使用以及在template三元运算符中内使用过滤
    新建filters.js如下,内容过滤可以自己写函数,记得export导出importdayjsfrom"dayjs";//转小写letlower=value=>value.toLowerCase();//转大写letupper=value=>value.toUpperCase();letcurrencyStyle=(value,style)=>{//货币格式/***sty......
  • 2023.6.13 数组中不等三元组的数目
    直接的思路是三重循环\(O(n^3)\)解决,由于数据范围是\(n\leq100\),所以\(n^3\leq10^6\)可以过。如果想稍微优化一下的话,可以考虑下面两种思路,都是类似的:排序,排完序后相同的元素会聚集到一起,假设他们聚集在了区间\([i,j]\)内。那\([0,i-1]\)这一部分区间和\([j+1,n]\)......
  • 力扣---2475. 数组中不等三元组的数目
    给你一个下标从0开始的正整数数组nums。请你找出并统计满足下述条件的三元组(i,j,k)的数目:0<=i<j<k<nums.lengthnums[i]、nums[j]和nums[k]两两不同。换句话说:nums[i]!=nums[j]、nums[i]!=nums[k]且nums[j]!=nums[k]。返回满足上述条件三元组的数目......
  • R:三元图
    setwd("D:\\Desktop")library(tidyverse)#数据处理函数data_clean<-function(otu,design,type=c("relative","absolute"),threshold=0.001,times=100){#函数测试数据#library(amplicon)#otu=otutab#metadata$SampleID=rownames(m......
  • 三元图
    三元图(TernaryPlot)广泛用于三个分组数据比较、筛选,通过三元图可以直观展示数据在三个分组的分布情况,高效率地筛选离群元素,同时配合方差分析等统计检验方法可以找到不同分组中显著富集的元素。三元图由三个坐标轴组成等边三角形,轴上数值代表对应分组占比数值,三个顶点标注的信息代......
  • 二分法 三元表达式 生成式 匿名函数 内置函数
    目录二分法三元表达式生成式列表生成式字典生成式集合生成式元组生成式(生成器)匿名函数内置函数二分法二分法思路1.二分法的使用前提条件:列表中得数字必须要有序2.将对象整除2分成两部分3.将目标数值与分割后的对象做比较来确定目标数值在哪一部分4.继续重复这两个步骤直至......
  • 算法之二分法、三元表达式、列表生成式、字典生成式(了解)、匿名函数、常见的内置函数
    算法之二分法二分概念二分算法,又称折半查找,即在一个单调有序的集合中查找一个解。每次分为左右两部分,判断解在哪个部分中并调整上下界,直到找到目标元素,每次二分后都将舍弃一半的查找空间。定义and实现:算法就是解决问题的高效办法常见的算法:二分法算法还可以锻炼我们的......
  • day16 Python下的三元运算符
    Python下的三元运算符【一】引言三元表达式(三目运算符)能够简洁我们的代码三元表达式其实是将if...else...判断语句的简化表达,代替很多ifelse和if-else一样,只有一个表达式会被执行。因此,三元表达式中的if和else可以包含大量的计算,但只有True的分支会被执行在Java、C......