根据题目描述,原图为二分图,设两侧点集为 \(S,T\),大小为 \(s,t(s\le 3\times 10^5,t\le 3\times 10^3)\)。
注意到有四元环当且仅当 \(T\) 中存在一个点对 \((a,b)\) 同时和 \(S\) 中的某两个点连边。
可以先考虑暴力,一种想法是:考虑枚举 \(S\) 中的点 \(c\),设和 \(c\) 连边的点的集合为 \(Tc\)。
对所有满足 \(a,b\in Tc,a\neq b\) 的点对打上标记 \(tag(a,b)=c\),表示 \(a,b\) 同时和 \(c\) 有连边。
如果已经被打上标记,说明有四元环 \(a-tag(a,b)-b-c\)。
如果到最后都没有出现,输出 \(-1\)。
这种做法的时间复杂度是多少?
我们发现 \(T\) 中只有 \(\dfrac{t(t-1)}{2}\) 个点对,根据鸽巢原理,最多打 \(\dfrac{t(t-1)}{2}+1\) 个标记就会重复访问同一个点对,即出现一个四元环。
所以时间复杂度 \(O(s+t^2)\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5, M = 3005;
vector<int> e[N];
int a[M][M], s, t, m;
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> s >> t >> m;
for(int i = 1; i <= m; i ++)
{
int x, y; cin >> x >> y;
e[x].push_back(y - s);
}
for(int i = 1; i <= s; i ++)
{
for(int j = 0; j < e[i].size(); j ++)
{
for(int k = j + 1; k < e[i].size(); k ++)
{
int x = e[i][j], y = e[i][k];
if(a[x][y])
{
cout << x + s << " " << a[x][y] << " " << y + s << " " << i;
return 0;
}
a[x][y] = a[y][x] = i;
}
}
}
cout << -1;
return 0;
}
标签:标记,int,题解,复杂度,四元,ABC260F,dfrac
From: https://www.cnblogs.com/adam01/p/18327137