CF1439B. Graph Subset Problem

给出一个无向图,你需要找到任意一个大小为\(k\)的团,或者一个点集满足每个点和点集内的点有至少\(k\)条连边。

输出方案。

\(n,m,k\le 10^5\)

无重边自环。


大FST题……

比赛结束后因为自己没有调出来而感觉到不甘心,改出来之后忽然发现其实比赛的时候没有AC这题很正常的……

还有写哈希习惯性开那个接近\(2*10^7\)的数字,发现空间挂了开了接近\(10^6\)的数字,却没有想过开\(10^7\)的数字,我在干嘛……

首先尝试找点集。类似拓扑排序,每次将度数小于\(k\)的点删掉,一直做。如果最后还有点剩余,就说明找到了点集。

如果找不到点集,就要尝试找团。再做一遍上面的操作,将限制改成\(k-1\)

现在得到了一个新图,每个点的度数至少为\(k-1\)。接着判断度数为\(k-1\)的点是否在一个团内,判断的时候可以\(O(k^2)\)(这里我写了哈希,假装它的复杂度是常数级别),如果判断出来就输出,如果判断不出来,将这个点以及其连边删去(这时候可能得到新的度数为\(k-1\)的点,丢入队列中操作)。

显然\(k\le\sqrt {2m}\),又由于每次操作会删去\(k-1\)条边,于是判断的操作只会做\(\frac{m}{k-1}\)次,那么时间复杂度就是\(O(mk)\)的。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 100005
#define ll long long
int n,m,k;
struct EDGE{
	int to;
	EDGE *las;
};
struct Graph{
	EDGE e[N*2];
	int ne;
	EDGE *last[N];
	void link(int u,int v){
		e[ne]={v,last[u]};
		last[u]=e+ne++;
	}
	void clear(){
		ne=0;
		memset(last,0,sizeof(EDGE*)*(n+1));
	}
} G;
int q[N],head,tail;
int deg[N];
int vis[N];
void BFS(int lim){
	memset(deg,0,sizeof(int)*(n+1));
	for (int i=1;i<=n;++i)
		for (EDGE *ei=G.last[i];ei;ei=ei->las)
			deg[i]++;
	head=1,tail=0;
	memset(vis,0,sizeof(int)*(n+1));
	for (int i=1;i<=n;++i)
		if (deg[i]<lim){
			q[++tail]=i;
			vis[i]=1;
		}
	while (head<=tail){
		int x=q[head++];
		for (EDGE *ei=G.last[x];ei;ei=ei->las)
			if (!vis[ei->to]){
				--deg[ei->to];
				if (deg[ei->to]<lim){
					q[++tail]=ei->to;
					vis[ei->to]=1;
				}
			}
	}
}
const int mo=10000007;
int BZ;
struct hsh{
	ll key;
	int bz,v;
} h[mo];
bool nei_query(int u,int v){
	ll key=(ll)u*(n+1)+v;
	int i=key%mo;
	for (;h[i].bz==BZ && h[i].key!=key;++i==mo?i=0:i);
	if (h[i].bz==BZ) return h[i].v;
	return 0;
}
void nei_set(int u,int v,int c){
	ll key=(ll)u*(n+1)+v;
	int i=key%mo;
	for (;h[i].bz==BZ && h[i].key!=key;++i==mo?i=0:i);
	h[i]={key,BZ,c};
}
int ls[N];
bool check(int x){
	int c=0;
	for (EDGE *ei=G.last[x];ei;ei=ei->las)
		if (nei_query(x,ei->to)==1)
			ls[++c]=ei->to;
	if (deg[x]<k-1){
		for (int t=1;t<=c;++t){
			nei_set(ls[t],x,0);
			if (--deg[ls[t]]==k-1)
				q[++tail]=ls[t];
		}
		return 0;
	}
	for (int i=1;i<=c;++i)
		for (int j=i+1;j<=c;++j)
			if (nei_query(ls[i],ls[j])==0){
				for (int t=1;t<=c;++t){
					nei_set(ls[t],x,0);
					if (--deg[ls[t]]==k-1)
						q[++tail]=ls[t];
				}
				return 0;
			}
	ls[++c]=x;
	return 1;
}
void BFS2(){
	++BZ;
	for (int i=1;i<=n;++i)
		if (!vis[i])
			for (EDGE *ei=G.last[i];ei;ei=ei->las)
				if (!vis[ei->to])
					nei_set(i,ei->to,1);
	for (int i=1;i<=n;++i)
		if (deg[i]==k-1)
			q[++tail]=i;
	while (head<=tail){
		int x=q[head++];
		if (check(x)){
			printf("2\n");
			for (int i=1;i<=k;++i)
				printf("%d ",ls[i]);
			printf("\n");
			return;
		}
	}
	printf("-1\n");
}
int main(){
//	freopen("in.txt","r",stdin);
	int T;
	scanf("%d",&T);
	while (T--){
		scanf("%d%d%d",&n,&m,&k);
		G.clear();
		for (int i=1;i<=m;++i){
			int u,v;
			scanf("%d%d",&u,&v);
			G.link(u,v);
			G.link(v,u);
		}
		if ((ll)k*(k-1)/2>m){
			printf("-1\n");
			continue;
		}
		BFS(k);
		if (tail<n){
			printf("1 %d\n",n-tail);
			for (int i=1;i<=n;++i)
				if (!vis[i])
					printf("%d ",i);
			printf("\n");
			continue;
		}
		BFS(k-1);
		BFS2();
	}
	return 0;
}

posted @ 2020-11-18 11:07  jz_597  阅读(316)  评论(0编辑  收藏  举报