[题解]CF1364-D Ehab's Last Corollary

很妙的一题

题意

给出\(n\)个节点\(m\)条边的无向连通图和参数\(k\),求:

  • 严格\(\lceil \frac{k}{2} \rceil\)大小的点独立集
  • 或大小$ k$的简单环

\(3 \leq k \leq n \leq 10^5,n-1 \leq m \leq 2 \cdot 10^5\)

思路

解法1

​ 我们求出一个原图的DFS树,当某个节点\(u\)存在反向边时,找出终点\(v\)深度最深的反向边.容易看出这个反向边在一个简单环中,且这个简单环不会被其他边分割.如果这个环的大小\(\leq k\),直接输出即可,否则我们取不相邻的\(\lceil \frac{k}{2} \rceil\)个点,它们形成一个点独立集.

​ 如果原图无环(或者说是一棵树),那么我们很容易就能求出大小\(\lceil \frac{k}{2} \rceil\)的点独立集.

解法2

​ 我们求出任意一个环,然后枚举所有的边\(1...m\).如果某条边把这个环分割开(即起点终点都在环上),那么保留这个环的任意一半,继续该过程.最后我们会得到一个不被其他边分割的简单环.之后的处理同解法1.

​ 如果原图是一棵树,同解法1.

​ (比赛时我用的就是这种做法,但是写T了=-=个人觉得这是最难想也最难写的做法,鬼知道我当时在干什么)

解法3

​ (来自Um_nik的代码)https://codeforces.com/contest/1364/submission/83636767

​ %%%%%

​ 根据原题,无论我们求点独立集还是简单环,都需要最多\(k\)个点,那么我们简单粗暴地把所有编号$ > k\(的点删掉,再在剩下的图(**注意新图可能不连通**)中寻找环.如果我们找到任意一个环,直接输出即可,因为这个环的大小肯定\)k\(.如果没有环(新图是一个森林),那也能很容易地找到\) $大小的点独立集.

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//D
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+10;
const int maxm = 4e5+10;
struct Edge{
int from,to,next,cnt;
Edge(int from = 0,int to = 0,int next = 0):from(from),to(to),next(next){}
}edge[maxn];
int head[maxn],cnt,d,dep[maxn],p[maxn];
bool vis[maxn],col[maxn];
void addedge(int f,int t){
edge[cnt] = Edge(f,t,head[f]);
head[f] = cnt++;
}
int n,m,k;
void DFS(int u){
if(vis[u])return;
vis[u] = 1;
for(int i = head[u];~i;i = edge[i].next){
int v = edge[i].to;
if(vis[v] and dep[v] > dep[u]){
vector<int>cir = {};
int cur = v;
while(cur != u){
cir.push_back(cur);
cur = p[cur];
}
cir.push_back(u);
int s = cir.size();
cout << 2 << endl << s << endl;
for(int yay:cir)cout << yay << " ";
exit(0);
}
else if(!vis[v]){
p[v] = u;
dep[v] = dep[u]+1;
col[v] = !col[u];
DFS(v);
}
}
}
int main(){
ios::sync_with_stdio(0);
memset(head,-1,sizeof(head));
cin >> n >> m >> k;
d = ceil((double)k/2);
for(int i = 1;i <= m;i++){
int f1,t1;
cin >> f1>> t1;
if(f1 > k or t1 > k)continue;
addedge(f1,t1);
addedge(t1,f1);
}
int cnt1 = 0;
for(int i = 1;i <= n;i++)DFS(i);
vector<int>ans = {};
for(int i = 1;i <= n;i++)if(col[i])cnt1++;
int qwq = 0;
if(cnt1 >= d)qwq = 1;
for(int i = 1;i <= n;i++)if(col[i] == qwq){
if((int)ans.size() == d)break;
ans.push_back(i);
}
cout << 1 << endl;
for(int x:ans)cout << x << " ";
return 0;
}