dfs树

dfs树是解决图中带环的利器。

前天CF的F题就是dfs树,但是当时我没有认真思考 觉着找到一个环过于困难 当时没有想到 也没理解dfs树的意义。

对于一张无向图求出一个dfs树 这个树有两种边 树边和非树边。

其中非树边连接的u v 他们一定具有祖先关系。

$注:这是一个很显然 也十分重要的性质。

应用:CF1325F Ehab's Last Theorem

给出一张无向联通图 且不存在重边 自环。定义\(m=\lceil sqrt(n)\rceil\)

求出图中一个环S 满足S是一个简单环 且\(|S|\geq m\)

或者求出图中一个independent set W 满足 W=m

求环或者求独立集 我们考虑一张无向图 很难求出最大的独立集 但是只是让求出一个大小为m的独立集。

考虑如何求环 dfs树。但是求不了最大环 但是我们要的也不是最大。我们利用非树边判断环的大小。

由于没有重边 自环 所以一个点连出w条非树边 那么显然有大小为w+1的环。

如果所有点都没有构成大小>=m的环 那说明每个点都最多有 m-2条非树边。

这个时候考虑最大独立集 当前点我们加入到我们的集合中 然后其最多影响m-2个点。

把能影响的都给标记了 最后我们发现最多能选 \(\lceil \frac{n}{m-1}\rceil\)个点 可以证明这个东西>=m.证毕。

所以我们直接上dfs树即可。值得注意的是 最后构造独立集的时候 需要从叶子节点构造。

可以证明 这样对其他节点的影响如上面的分析一样。

const int MAXN=200010;
int n,m,len=1,w,top,flag,cc;
int vis[MAXN],s[MAXN],d[MAXN],mark[MAXN],q[MAXN];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
inline void add(int x,int y)
{
	ver[++len]=y;nex[len]=lin[x];lin[x]=len;
	ver[++len]=x;nex[len]=lin[y];lin[y]=len;
}
inline void dfs(int x,int las)
{
	if(flag)return;
	vis[x]=1;s[++top]=x;
	go(x)
	{
		if((i^1)==las)continue;
		if(flag)break;
		if(!vis[tn])
		{
			d[tn]=d[x]+1;
			dfs(tn,i);
		}
		else if(d[x]-d[tn]+1>=w)
		{
			put(2);
			put(d[x]-d[tn]+1);
			int ww=d[x]-d[tn]+1;
			while(ww)
			{
				printf("%d ",s[top]);
				--top;--ww;
			}
			flag=1;
		}
	}
	--top;
	if(!mark[x])
	{
		q[++cc]=x;
		go(x)mark[tn]=1;
	}
}

int main()
{
	freopen("1.in","r",stdin);
	get(n);get(m);
	rep(1,m,i)add(read(),read());
	w=(int)ceil(sqrt(n*1.0));
	//put(w);
	dfs(1,-1);
	if(flag)return 0;
	put(1);rep(1,w,i)printf("%d ",q[i]);
	return 0;
}

当然dfs树还有应用 如上次我写了一道bzoj 的电压 那道题是真的比较妙 dfs树上差分。最后证明的是 其他环都是无效的 有dfs树上的环即可。

一道例题:LINK:2115 Wc2011 Xor

给出一张有向无环图 求出1~n的一条路径使得其xor和最大。路径可以经过同一条边同一个点 不过这样的路径的价值被计算相应次数。

显然一条路径出现两次相当于没出现。如何求这样的路径。可以考虑线性基求最大值。

posted @ 2020-03-16 20:09  chdy  阅读(1094)  评论(0编辑  收藏  举报