CF 1440D Graph Subset Problem

题目描述

https://codeforces.com/contest/1440/problem/D

Solution

首先考虑能否求出一个合法的子集

那么显然就是把所有度数小于 $k$ 的点都删掉,如果还有点剩下,那么这些点就是合法的一个集合

现在我们考虑如何求一个大小为 $k$ 的团,首先如果 $\frac{k(k-1)}{2}>m$ 则一定不存在这样的团

我们考虑在删点过程中只找度数为 $k-1$ 的点,遍历它的所有出边,然后 $O(k^2)$ 判断这些点能否组成一个团

因为如果存在大小为 $k$ 的团,我们会在求子集的时候考虑,否则如果只存在大小为 $k$ 的团,则在删点的过程中一定能找到至少一个度数为 $k-1$ 的点

大致证明如下,如果所有点的度数都大于 $k-1$,则不会被删

否则它最多被删到度数为 $k-1$

注意到如果一个度数为 $k-1$ 的点不能组成团,一定要把它删掉

这样的做的复杂度为 $O(\frac{m}{k}k^2)=O(mk)$

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <cstring>
#include <algorithm>
#define maxn 100010
#define pb push_back
using namespace std;

int n, m, k;

struct Edge {
int to, next;
} e[maxn * 2]; int c1, head[maxn], du[maxn];
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

vector<int> E[maxn];
bool check(vector<int> &a) { // 事实证明 vector 跑的最快
for (auto u : a)
for (auto v : a) {
if (u == v) break;
if (!binary_search(E[u].begin(), E[u].end(), v)) return 0;
}
return 1;
}

int vis[maxn];
void init() {
memset(head, -1, sizeof head);
for (int i = 1; i <= n; ++i) head[i] = -1, E[i].clear(), du[i] = vis[i] = 0;
c1 = 0;
}

void work() {
cin >> n >> m >> k; init();
for (int i = 1; i <= m; ++i) {
int x, y; cin >> x >> y;
add_edge(x, y); add_edge(y, x);
++du[x]; ++du[y];
E[x].pb(y); E[y].pb(x);
} queue<int> Q;
for (int i = 1; i <= n; ++i)
sort(E[i].begin(), E[i].end());
for (int i = 1; i <= n; ++i)
if (du[i] < k) Q.push(i);
while (!Q.empty()) {
int u = Q.front(); Q.pop(); vis[u] = 1;
if (du[u] == k - 1 && 1ll * k * (k - 1) / 2 <= m) {
vector<int> clique = { u };
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (vis[v]) continue;
clique.pb(v);
}
if (check(clique)) {
cout << 2 << "\n";
for (auto u : clique) cout << u << " ";
cout << "\n"; return ;
}
}
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (--du[v] == k - 1) Q.push(v);
}
}
int s = 0;
for (int i = 1; i <= n; ++i) s += du[i] >= k;
if (s) {
cout << 1 << " " << s << endl;
for (int i = 1; i <= n; ++i)
if (du[i] >= k) cout << i << " ";
cout << "\n"; return ;
}
cout << "-1\n";
}

int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);

int T; cin >> T;
while (T--) work();
return 0;
}