CF1470D Strange Housing【二分图】归纳构造

CF1470D Strange Housing

给定一个无向图,你要找到一个独立集,对于一条边,如果 \(u,v\) 都不在独立集里,则删去这条边。

求满足删完后原图仍联通的独立集。\(n\le 10^5\)

先把原图不联通的情况判掉。

对于类似独立集/匹配染色的构造题,我们可以先从二分图入手,从特殊情况启发得到正解。

如果原图是二分图,那么我们随便选一侧的点染色,显然正确。我们假定对所有左部点染色。

现在考虑原图不是二分图的情况,在二分图且已经染完色的基础上,左部和右部的点之间都有边,但如果左部有边是不合法的,我们就调整二分图,使得左部的点之间都无边,而对于右部内部的边,删掉显然是不影响连通性的。

那我们维护构造左部的过程即可,先随便放一个点进去,将其相连的点都从左部待选点移出,再判断这些点相连的点是否仍在左部待选点里,如果是就放左部,否则放右部。可以发现,这样构造一定能结束。

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int read(){
	char c=getchar();int h=0,tag=1;
	while(!isdigit(c)) tag=(c=='-'?-1:1),c=getchar();
	while(isdigit(c)) h=(h<<1)+(h<<3)+(c^48),c=getchar();
	return h*tag;
}
void fil(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
}
const int N=3e5+500;
vector<int>s[N];
int lft[N],vis[N];
void dfsR(int x);
void dfsL(int x) {
	vis[x]=1;
	for(int y:s[x]) {
		lft[y]=1;
		
	}
	for(int y:s[x]) {
		dfsR(y);
	}
}
vector<int>ans;
void dfsR(int x) {
	vis[x]=1;
	for(int y:s[x]) {
		if(lft[y]==0) ans.push_back(y),lft[y]=1,dfsL(y);
	}
}
void work() {
	int n=read(),m=read();
	for(int i=1;i<=n;i++) {
		s[i].clear();vis[i]=lft[i]=0;
	}
	ans.clear();
	for(int i=1;i<=m;i++) {
		int u=read(),v=read();s[u].push_back(v);s[v].push_back(u);
	}
	lft[1]=1;
	ans.push_back(1);
	dfsL(1);
	for(int i=1;i<=n;i++) {
		if(vis[i]==0) return puts("NO"),void();
	}
	puts("YES");
	cout<<ans.size()<<endl;
	for(int x:ans) {
		cout<<x<<" ";
	}
	cout<<"\n";
}
int main(){
//	fil();
	int T=read();
	while(T--) work();	
	return 0;
}

实际上,如果不从二分图的角度,而是站在归纳法上看,或许更为清晰:

对于 \(n=1\),染色即可。

对于 \(n>1\),前 \(n-1\) 个点是一个合法的方案(连通图),我们希望加进 \(n\),如果 \(n\) 相连的点全部没染色,则 \(n\) 必须染色,否则存在一个相连的点染色,那么 \(n\) 就必须不能染色。显然这样也一定会结束并构造成功。

posted @ 2024-08-26 18:02  Apricity8211  阅读(5)  评论(0编辑  收藏  举报