【Codeforces】CF Round 866 (Div. 2) E.The Fox and the Complete Tree Traver | 树

1,296 阅读2分钟

【Codeforces】Codeforces Round 866 (Div. 2) E.The Fox and the Complete Tree Traver | 树

题目链接

Problem - E - Codeforces

题目

image.png

题目大意

在一棵有 nn 个节点的树上,狐狸可以从顶点 vv 跳跃到另一个顶点 uu 当且仅当这些顶点之间的距离不超过 22

换句话说,如果顶点 vvuu 之间有边直接相连,或者存在这样的顶点 ww 使得顶点 vvww 之间有边、顶点 uuww 之间有边,狐狸就可以在一次跳跃中从顶点 vv 到达顶点 uu

求树上是否有循环路线 v1,v2,...,vnv_1,v_2,...,v_n 使得:狐狸可以从顶点 viv_i 跳到顶点 vi+1v_{i+1},狐狸可以从顶点 vnv_n 跳到顶点 v1v_1,且所有 viv_i 是成对不同的。

思路

容易通过手玩发现如果树上存在下图所示结构那么一定无解。

image.png

所以有解的树一定是一条链上挂着若干个叶子节点的结构。

我们首先要 check 整棵树是否是有解的形状,只需要将所有度为 11 的节点删除,若剩下的节点不是一条链即无解,如果剩下的部分存在度大于 22 的节点即可说明不是链。

image.png

在有解的情况下,一种合法的构造解的方案是:

首先将剩下的链拎出来,即用数组 ansans 顺序存储图中的橙色节点。

先正着遍历一遍 ansans 数组,遍历到第 ii 个节点时,若 ii 为奇数就输出橙色节点 ans[i]ans[i],否则输出节点 ii 上挂着的绿色节点。

再倒着遍历一遍 ansans 数组,遍历到第 ii 个节点时,若 ii 为偶数就输出橙色节点 ans[i]ans[i],否则输出节点 ii 上挂着的绿色节点。

上图的遍历结果如下所示。

image.png

代码

#include <bits/stdc++.h>
using namespace std;
const int N=200005;
int n,d[N],ans[N],tot;
vector<int>e[N],t;
int main()
{
	scanf("%d",&n);
	for (int x,y,i=1;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		e[x].push_back(y);
		e[y].push_back(x);
		d[x]++;
		d[y]++;
	}
	for (int i=1;i<=n;++i)
		if (d[i]==1) t.push_back(i),d[i]=0;
	for (auto i:t)
		for (auto v:e[i]) d[v]--;
	int id=1;
	for (int i=1;i<=n;++i)
	{
		if (d[i]==1) id=i;
		if (d[i]>2) return printf("No\n"),0;
	}
	printf("Yes\n");
	memset(d,0,sizeof(d));
	for (int i=id,fa=0,flg=1;flg;)
	{
		ans[++tot]=i;
		flg=0;
		for (auto v:e[i])
			if (v!=fa&&e[v].size()!=1)
			{
				fa=i;
				i=v;
				flg=1;
				break;
			}
	}
	for (int i=1;i<=tot;++i)
	{
		if (i&1) printf("%d ",ans[i]);
		else 
		{
			for (auto v:e[ans[i]])
				if (v!=ans[i-1]&&v!=ans[i+1]) printf("%d ",v);
		}
	}
	for (int i=tot;i>=1;--i)
	{
		if (i&1)
		{
			for (auto v:e[ans[i]])
				if (v!=ans[i-1]&&v!=ans[i+1]) printf("%d ",v);
		}
		else printf("%d ",ans[i]);
	}
	return 0;
}