Codeforces 1325F Ehab's Last Theorem
题目大意
给出一幅 \(n\) 个点,\(m\) 条边的无向连通图。让你找出至少有 \(\lceil \sqrt{n} \rceil\) 个点的简单环,或正好有 \(\lceil \sqrt{n} \rceil\) 个点的最大独立集。(两者选其一)
如找的是最大独立集,输出1并输出最大独立集的顶点。
如找的是环,输出2,输出环的顶点个数并输出环的所有顶点。
\((5 \le n \le 10^5, n-1 \le m \le 2 \cdot 10^5)\)
题解
对于无向图的连通性问题,我们首先考虑它的DFS树。
若结点 \(u\) 有大于等于 \(\lceil\sqrt n\rceil-1\) 条后向边,则一定存在长度大于等于 \(\lceil\sqrt n\rceil\) 的简单环。
否则若当前构造的独立集中没有点与 \(u\) 相邻,我们就把结点 \(u\) 加入独立集。
若最终没有找到大于 \(\lceil\sqrt n\rceil\) 的简单环,那么构造出的独立集一定是大于等于 \(\lceil\sqrt n\rceil\) 的。因为选择一个点加入独立集至多只会导致和它相邻的 \(\lceil\sqrt n\rceil-2\) 个点无法被加入独立集。
Code
#include <bits/stdc++.h>
using namespace std;
#define RG register int
#define LL long long
template<typename elemType>
inline void Read(elemType& T) {
elemType X = 0, w = 0; char ch = 0;
while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
T = (w ? -X : X);
}
struct Graph {
struct edge { int Next, to; };
edge G[400010];
int head[100010];
int cnt;
Graph() :cnt(2) {}
void clear(int n) {
cnt = 2;fill(head, head + n + 2, 0);
}
void add_edge(int u, int v) {
G[cnt].to = v;
G[cnt].Next = head[u];
head[u] = cnt++;
}
};
Graph G;
vector<int> cycle, s, path;
int dfn[100010], deep[100010];
bool mark[100010], findans;
int N, M, sq, Index;
void DFS(int u, int fa) {
if (findans) return;
path.push_back(u);
dfn[u] = ++Index;
int num = 0;
bool flag = true;
for (int i = G.head[u];i;i = G.G[i].Next) {
if (findans) return;
int v = G.G[i].to;
if (!dfn[v] && v != fa) { deep[v] = deep[u] + 1;DFS(v, u); }
else ++num;
if (mark[v]) flag = false;
}
if (findans) return;
if (num >= sq - 1) {
for (int i = G.head[u];i;i = G.G[i].Next) {
int v = G.G[i].to;
if (dfn[v] && dfn[v] < dfn[u]) {
if (deep[u] - deep[v] >= sq - 1) {
while (path.back() != v) {
cycle.push_back(path.back());
path.pop_back();
}
cycle.push_back(v);
findans = true;
return;
}
}
}
}
if (flag) { s.push_back(u);mark[u] = true; }
path.pop_back();
}
int main() {
Read(N);Read(M);
for (int i = 1;i <= M;++i) {
int u, v;
Read(u);Read(v);
G.add_edge(u, v);
G.add_edge(v, u);
}
sq = 1;
while (sq * sq < N) ++sq;
DFS(1, 0);
if (findans) {
printf("2\n");
printf("%d\n", cycle.size());
for (auto x : cycle)
printf("%d ", x);
printf("\n");
}
else {
printf("1\n");
for (int i = 0;i < sq;++i)
printf("%d ", s[i]);
printf("\n");
}
return 0;
}