题目链接
https://codeforces.com/problemset/problem/1440/D
题意
给出一张图,问是否出现
- 大小为K的强联通子图
- K个节点具有K个以上邻居的点集
思路
第二种最好求,利用拓扑排序思路,所有度小于k的点入队,挨个删点,更新度数,直到队空,如果没入队的节点数大于等于k,那么存在第二类。
第一种较麻烦,大小为k的子图每个节点度数一定为k-1,子图是原图不断删点生成的,这个过程正好是第二种求取过程。在队列每次取出点时,如果其度数是k-1,就将它所有邻居(已经入队并且取出的除外,这种节点已经被验证过不能形成第一种情况了)加入集合,枚举集合内节点,通过二分查找判断是否联通即可。
注意时间比较紧,可以判断边,当且仅当m*2>(k-1)*k才有可能形成第一种,可以进行优化。
代码
```#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
typedef long long ll;
const int maxn=100050;
const int inf=0x3f3f3f3f;
int n,m;
vector<int>e[maxn];
int du[maxn];
int inqueue[maxn];
void init(int n){//memset再次杀我 ^^
for(int i=0;i<=n;i++) {
e[i].clear();
inqueue[i]=0;
du[i]=0;
}
}
template <typename T>
void read(T &x){
x=0;
char ch=getchar();
ll f=1;
while(!isdigit(ch)){
if(ch=='-')
f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-48;
ch=getchar();
}
x*=f;
}
signed main(){
IOS
#ifndef ONLINE_JUDGE
freopen("D:\\code\\IO\\in.txt","r",stdin);
freopen("D:\\code\\IO\\out.txt","w",stdout);
#endif
int tn;
read(tn);
while(tn--){
int k;
read(n),read(m),read(k);
init(n);
for(int i=1;i<=m;i++){
int u,v;
read(u),read(v);
e[u].push_back(v),e[v].push_back(u);
du[u]++,du[v]++;
}
for(int i=1;i<=n;i++){
sort(e[i].begin(),e[i].end());//维护节点有序,便于二分查找
}
queue<int>q;
for(int i=1;i<=n;i++){
if(du[i]<k) q.push(i),inqueue[i]=1;//两类答案都需要度至少为k
}
vector<int>c,ans;
while(q.size()){
int u=q.front();q.pop();
inqueue[u]=2;//加入了队列,且取出过
for(auto i:e[u]){//删点更新
du[i]--;
if(inqueue[i]) continue;
if(du[i]<k) q.push(i),inqueue[i]=1;
}
if(m*2>=k*(k-1)){//边的限制条件
if(du[u]==k-1&&c.empty()){//度为k-1的点可能形成集团
c.push_back(u);
for(auto i:e[u]) //有三种状态,0,1,2。0的代表度大于k有可能满足条件,2的度小于k,被取出过,那包含他的集团一定不满足条件
if(inqueue[i]!=2)c.push_back(i);
bool ok=1;
for(int i=0;i<c.size();i++){
for(int j=i+1;j<c.size();j++){
if(!binary_search(e[c[i]].begin(),e[c[i]].end(),c[j])){
ok=0;
break;
}
}
if(!ok) break;
}
if(!ok) c.clear();
}
}
}
for(int i=1;i<=n;i++){
if(!inqueue[i] )ans.push_back(i);
}
if(ans.size()>=k){
printf("1 %d\n",ans.size());
for(int i=0;i<ans.size();i++){
if(i) putchar(' ');
printf("%d",ans[i]);
}
putchar('\n');
}
else if(c.size()){
printf("2\n");
for(int i=0;i<c.size();i++){
if(i) putchar(' ');
printf("%d",c[i]);
}
putchar('\n');
}
else
printf("-1\n");
}
return 0;
}