三元环计数问题

三元环计数问题

link,给定一个无向图,求其中三元环的数量。

1n1051 \le n \le 10^51m2×1051 \le m \le 2 \times 10^5

构造一个这样的有向图:对于原来图中的每一条无向边,改为由度数小的向度数大的连边,若相等则由编号小的向编号大的连边,在这样的图中,三元环 {x,y,z}\{ x,y,z\} ,度数最小或编号最小的点回向另外两点连边,所以边肯定是 xyx \rightarrow yxyx \rightarrow yyzy \rightarrow z 这种形式的。这样枚举 xx,标记所有 xx 出去的点 yy ,在枚举这些点出去的点 zz ,若 zz 被标记了说明构成三元环。

这样的时间复杂度是 Θ(mm)\Theta(m \sqrt m),为什么呢?我们枚举 xx 出去的 yy 相当于枚举了每条边,这是 Θ(m)\Theta(m);枚举 yy 后还要枚举 zz,为什么这个东西的复杂度是 Θ(m)\Theta(\sqrt m) 呢?现在我们要证明每个点的出度不可能大于m\sqrt m

反证法,若一个点的出度 >m> \sqrt m,因为一个点只能连向度数大于等于它的点,所以它出去的 m\sqrt m 个点出度也都 >m> \sqrt m 个点,这样两个 >m> \sqrt m 相乘,总边数就 >m> m,与 mm 条边矛盾,因此每个点的初度 m\le \sqrt m,复杂度就是 Θ(mm)\Theta(m \sqrt m) 了。

CODE

#include <bits/stdc++.h>
using namespace std;

inline int read() {
	int x = 0, f = 0; char c = 0;
	while (!isdigit(c)) f |= c == '-', c = getchar();
	while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return f ? -x : x;
}

#define N 100010
#define M 200010
#define pb push_back

int n, m, x[M], y[M], deg[N], vis[N];
vector<int> e[N];

int main() {
	n = read(), m = read();
	for (int i = 1; i <= m; i ++) {
		x[i] = read(), y[i] = read();
		deg[x[i]] ++, deg[y[i]] ++;
	}

	for (int i = 1; i <= m; i ++) {
		if (deg[x[i]] < deg[y[i]] || deg[x[i]] == deg[y[i]] && x[i] < y[i]) e[x[i]].pb(y[i]);
		else e[y[i]].pb(x[i]);
	}

	int res = 0;
	for (int i = 1; i <= n; i ++) {
		for (auto j : e[i]) vis[j] = 1;
		for (auto j : e[i]) for (auto k : e[j]) if (vis[k]) res ++;
		for (auto j : e[i]) vis[j] = 0;
	}

	printf("%d\n", res);
	return 0;
}

三元环计数问题
https://ybwa.github.io/p/a962ef89/
作者
yb
发布于
2021年11月6日
许可协议