题目描述
给定一个无向图,问这个图中是否存在三元环,或者这个图的补图中是否存在三元环。
正解
三元环计数有一个很经典的根号分治的做法,这里不详细讲,网上博客讲得很清楚。
补图的边是 级别的,就不能三元环计数了,怎么办?
由于边很多,随机三个点找到三元环的概率很大,直接随他大概 次就行。
时间复杂度 。(
)
代码
#include <bits/stdc++.h>
#define N 50005
using namespace std;
int n, m;
int x[N], y[N], deg[N];
int p[N], tot;
vector<int> g[N];
unordered_map<int, int> f[N];
inline int read() {
int x = 0; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int main() {
srand(time(0));
int Case = read();
while(Case--) {
n = read(), m = read();
for(int i = 1; i <= n; ++i) {
vector<int>().swap(g[i]);
f[i].clear();
}
for(int i = 1; i <= m; ++i) {
x[i] = read(), y[i] = read();
g[x[i]].push_back(y[i]), f[x[i]][y[i]] = true;
g[y[i]].push_back(x[i]), f[y[i]][x[i]] = true;
}
tot = 0;
int bl = sqrt(m);
for(int i = 1; i <= n; ++i) {
if(g[i].size() > bl) {
p[++tot] = i;
} else {
for(auto v1 : g[i])
for(auto v2 : g[i])
if(v1 != v2 && f[v1].count(v2))
goto found;
}
}
for(int i = 1; i <= tot; ++i)
for(int j = i + 1; j <= tot; ++j)
for(int k = j + 1; k <= tot; ++k)
if(f[i].count(j) && f[j].count(k) && f[k].count(i))
goto found;
for(int t = 1, x, y, z; t <= 500000; ++t) {
x = rand() % n + 1, y = rand() % n + 1, z = rand() % n + 1;
if(x == y || x == z || y == z) continue;
if(!f[x].count(y) && !f[y].count(z) && !f[z].count(x))
goto found;
}
puts("no");
continue;
found :
puts("yes");
}
return 0;
} 
京公网安备 11010502036488号