CF1439B Graph Subset Problem
https://www.luogu.com.cn/problem/CF1439B
k k k显然 ≤ n \le \sqrt{n} ≤n
首先度数 < k − 1 < k-1 <k−1的点及其相连的边是没用用的
所以可以先把这些点扔掉,剩下的点度数一定是 ≥ k − 1 \ge k-1 ≥k−1的
如果不存在度数为 k − 1 k-1 k−1的点,那么吧其中一个联通块拿出来就是第一类的答案
否则枚举 k − 1 k-1 k−1度点,然后 k 2 k^2 k2枚举它的所有邻居,用map判断是否有连边,用unordered_map可以去掉log
因为这样的点一定不会超过 n / k n/k n/k个,所以时间复杂度是 n / k ∗ k 2 = O ( n k ) ≤ O ( n n ) n/k*k^2=O(nk)\le O(n\sqrt{n}) n/k∗k2=O(nk)≤O(nn)
#include<bits/stdc++.h>
#define N 400050
using namespace std;
inline int read() {
int x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ) ch = getchar();
for(; ch >= '0' && ch <= '9'; ) x = (x << 3) + (x <<1) + (ch - '0'), ch = getchar();
return x;
}
int n, m, k, vis[N], in[N];
unordered_map<int, int> mp[N];
vector<int> g[N];
queue<int> q;
int check(int u) {
// if(u == 23 && k == 3) {
// printf("** %d %d %d %d %d %d %d\n", u, in[u], n, m, k, in[54], in[41]);
// for(int i = 1; i <= n; i ++) printf("%d ", in[i]); printf("\n");
// }
// printf("** %d %d\n", u, in[u]);
// for(int i = 1; i <= n; i ++) printf("%d ", in[i]); printf("\n");
if(in[u] != k - 1) return 0;
if(1ll * k * (k - 1) / 2 > m) return 0;
for(auto x : g[u]) if(!vis[x]) {
for(auto y : g[u]) if(!vis[y]) {
if(x == y) continue;
if(!mp[x][y]) return 0;
}
}
return 1;
}
void solve() {
n = read(), m = read(), k = read();
for(int i = 1; i <= n; i ++) {
vis[i] = 0, in[i] = 0, mp[i].clear();
vector<int> ls; ls.clear(); g[i].swap(ls);
}
for(int i = 1; i <= m; i ++) {
int u, v;
u = read(), v = read();
in[u] ++, in[v] ++;
g[u].push_back(v), g[v].push_back(u);
mp[u][v] = mp[v][u] = 1;
}
while(q.size()) q.pop();
for(int i = 1; i <= n; i ++) if(in[i] < k) {
q.push(i);
}
while(q.size()) {
int u = q.front(); q.pop();
// printf("** %d ** ", u);
if(vis[u]) continue;
if(check(u)) {
printf("2\n");
printf("%d ", u);
for(int x : g[u]) if(!vis[x]) printf("%d ", x); printf("\n");
return ;
}
vis[u] = 1;
for(int v : g[u]) {
if(vis[v]) continue;
in[v] --;
if(in[v] < k) {
q.push(v);
}
}
}
int f = 0;
for(int i = 1; i <= n; i ++) if(!vis[i]) {
f = 1;
// printf("* %d %d\n", i, in[i]);
break;
}
if(!f) {
printf("-1\n");
return ;
}
//for(int i = 1; i <= n; i ++) printf("%d ", in[i]); printf(" %d\n", f);
if(f == 1) {
int gs = 0;
for(int i = 1; i <= n; i ++) gs += (in[i] >= k);
printf("1 %d\n", gs);
for(int i = 1; i <= n; i ++) if(in[i] >= k) printf("%d ", i); printf("\n");
return ;
}
}
int t;
int main() {
t = read();
while(t --) solve();
return 0;
}
/*
1
10 15 1
1 2
2 3
3 4
4 5
5 1
1 7
2 8
3 9
4 10
5 6
7 10
10 8
8 6
6 9
9 7
*/