Link.
Description.
给定一张图,定义一个点集是好的,当且仅当它是一个大小为 \(K\) 的团(だんご)或它所有点都有至少 \(K\) 个在集合内的邻居。
问一张图是否存在一个点集是好的,若有输出一个方案,否则输出无解。
Solution.
如果没有第二种好点集,那恭喜你,你成功解决了 NPC 问题(笑)。
关键考虑第二种点集有什么能让这题从 NPC 变成可解题的性质。
考虑第二种点集不是第一种的,肯定存在一个点它度数为 \(K-1\),所以直接在那个点处判断即可。
然后考虑如何判断是否存在第二种点。
每次把 \(\deg <K\) 的删掉,最后看集合是不是空即可。
Coding.
点击查看 /tuu 代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;char c=getchar(),f=0;
for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=200005;int n,m,K,dg[N],fg[N];unordered_set<int>e[N];
inline bool chk(int x)
{
vector<int>v;for(auto y:e[x]) v.push_back(y);
for(auto y:e[x]) if((int)e[y].size()<K-1) return 0;
else for(auto z:v) if(y!=z&&e[y].find(z)==e[y].end()) return 0;
printf("2\n%d",x);for(auto y:v) printf(" %d",y);
return putchar('\n'),1;
}
inline void solve()
{
read(n,m,K);for(int i=1;i<=n;i++) dg[i]=0,e[i].clear(),fg[i]=0;
for(int i=1,x,y;i<=m;i++) read(x,y),e[x].insert(y),e[y].insert(x),dg[x]++,dg[y]++;
queue<int>q;for(int i=1;i<=n;i++) if(dg[i]<K) q.push(i);
while(!q.empty())
{
int x=q.front();q.pop();if(fg[x]) continue;else fg[x]=1;
if(1ll*K*(K-1)/2<=m&&dg[x]==K-1&&chk(x)) return;
for(auto y:e[x]) {e[y].erase(x),m--;if(--dg[y]<K) q.push(y);}
e[x].clear(),dg[x]=0;
}int cnt=n;for(int i=1;i<=n;i++) cnt-=fg[i];
if(cnt==0) return puts("-1"),void();else printf("1 %d\n",cnt);
for(int i=1;i<=n;i++) if(!fg[i]) printf("%d ",i);
putchar('\n');
}
int main() {int Ca;for(read(Ca);Ca--;) solve();return 0;}