F - Find 4-cycle
题意
给定一个二分图,其包含了S、T两个独立点集(即S、T各自内部间的任意两点之间不存在边),再给出S到T图中的M条无向边(S中的点与T中的点之间的边)。
求图中包含的一个四元环,若存在则输出环中包含的顶点,否则输出-1。
思路
二分图的环一定是偶数 那么四环图一定是两个点在S,两个点在T。
例如:
如何快速找到这四个点?定义st[u][v]的值为T集合中u、v两点与S集合中x相连接【话说官方题解中说用到的是抽屉原理,我不懂】。只需要枚举S中x2点对应的T中u、v点,如果st[u][v]在这之前已经存在值x1了,这时x1、x2、u、v四点构成一个四元环。
代码
有个需要注意的地方就是,S、T集合题目给定的点编号是T中的点按顺序排在S中点之后。比如S中有3个点 1、2、3,那么T中两个点的编号是4、5而不是1、2. 这时就要在存T集合的点时让其减掉S,不然st数组就爆了
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int S = 300010, T = 3010;
int s, t, m, st[T][T];
vector<int> g[S];
int main()
{
cin >> s >> t >> m;
// 这个题把T的编号排到了S之后 所以 需要先减到S 将下标离散化到从1开始
while (m--)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v - s);
}
//枚举S中的点Si,再枚举与其相连的T中的两个不同点u,v
//若u,v能连到S中的不同于Si的某点,则这四个点构成四元环
for (int i = 1; i <= s; i++)
for (auto &u : g[i])
for (auto &v : g[i])
{
if (u == v)
continue;
if (!st[u][v] || st[u][v] == i)
st[u][v] = st[v][u] = i;
else
{
cout << i << " " << u + s << " " << st[u][v] << " " << v + s << endl;
return 0;
}
}
cout << -1 << endl;
return 0;
}