【Codeforces】Codeforces Round 866 (Div. 2) E.The Fox and the Complete Tree Traver | 树
题目链接
题目
题目大意
在一棵有 个节点的树上,狐狸可以从顶点 跳跃到另一个顶点 当且仅当这些顶点之间的距离不超过 。
换句话说,如果顶点 和 之间有边直接相连,或者存在这样的顶点 使得顶点 和 之间有边、顶点 和 之间有边,狐狸就可以在一次跳跃中从顶点 到达顶点 。
求树上是否有循环路线 使得:狐狸可以从顶点 跳到顶点 ,狐狸可以从顶点 跳到顶点 ,且所有 是成对不同的。
思路
容易通过手玩发现如果树上存在下图所示结构那么一定无解。
所以有解的树一定是一条链上挂着若干个叶子节点的结构。
我们首先要 check 整棵树是否是有解的形状,只需要将所有度为 的节点删除,若剩下的节点不是一条链即无解,如果剩下的部分存在度大于 的节点即可说明不是链。
在有解的情况下,一种合法的构造解的方案是:
首先将剩下的链拎出来,即用数组 顺序存储图中的橙色节点。
先正着遍历一遍 数组,遍历到第 个节点时,若 为奇数就输出橙色节点 ,否则输出节点 上挂着的绿色节点。
再倒着遍历一遍 数组,遍历到第 个节点时,若 为偶数就输出橙色节点 ,否则输出节点 上挂着的绿色节点。
上图的遍历结果如下所示。
代码
#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;
}