Codeforces Round #628 (Div. 2) F. Ehab's Last Theorem(图论/dfs树输出环和独立集)

题目

给你一个n(5<=n<=1e5)个点m(n-1<=m<=2e5)条边的无向图,保证图连通

你可以选择以下两种之一来输出:

d=\left \lceil \sqrt{n} \right \rceil

①输出一个正好为d的独立集,输出这些点,使得两两之间无边

②输出一个长度不小于d的简单环,输出这些点

思路来源

https://www.bilibili.com/video/av96374512 dls的B站讲解

https://codeforces.com/contest/1325/submission/73249861 dls的F题代码

题解

Codeforces Round #628 (Div. 2) F. Ehab's Last Theorem(图论/dfs树输出环和独立集)_第1张图片

dfs树能用来判环,但可能会错过一些环,也不能保证环是最大环或最小环

但是,对于dfs树上不同的两棵子树内的点,它们之间一定没有边相连,不然就在一棵子树上了

因此,当u搜到已经访问过的v时,u和v一定同一棵子树,可用dep[u]-dep[v]+1确定环长

 

①若>=d的环可以被找出,则输出环,直接退出

②若未找出,说明对于此时的dfs树,u与距离为d-1的v之间无边,

每相距d-1之间的点无边,可通过深度同余d-1的点来确定独立集

显然,根据鸽巢原理,有\left \lceil \frac{n}{\left \lceil \sqrt{n} \right \rceil-1} \right \rceil \geqslant \left \lceil \sqrt{n} \right \rceil

故,取深度相同的最多的元素中的\left \lceil \sqrt{n} \right \rceil个元素,来确定最终的独立集即可

代码

#include
using namespace std;
const int N=1e5+10;
#define pb push_back
int n,m,d,dep[N],par[N],num[N];
bool vis[N];
vectore[N];
void dfs(int u){
	vis[u]=1;
	for(int v:e[u]){
		if(!vis[v]){
			par[v]=u;
			dep[v]=dep[u]+1;
			dfs(v);
		}
		else{
			if(dep[u]-dep[v]+1>=d){
				vectorcyc;
				for(int x=u;x!=v;x=par[x])cyc.pb(x);
				cyc.pb(v);
				puts("2");
				printf("%d\n",(int)(cyc.size()));
				for(int x:cyc)printf("%d ",x);
				exit(0);
			}
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	d=sqrt(n);if(d*d!=n)d++;
	for(int i=1;i<=m;++i){
		int u,v;
		scanf("%d%d",&u,&v);
		e[u].pb(v),e[v].pb(u);
	}
	dfs(1);
	for(int i=1;i<=n;++i){
		num[dep[i]%(d-1)]++;
	}
	int p=max_element(num,num+d-1)-num;
	vectorind;
	for(int i=1;i<=n;++i){
		if(dep[i]%(d-1)==p){
			ind.pb(i);
		}
	}
	ind.resize(d);
	puts("1");
	for(int x:ind){
		printf("%d ",x);
	}
	return 0;
} 

 

你可能感兴趣的:(#,图论基础)