题目链接:acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5866
题意:给一颗树,点集s中每个点a到树上所有点的距离序列都不同, 求对于所给树的最小点集s
思路:存成一个无向图,然后从入度最大的点开始dfs,可以画图看到每个节点除了父亲节点之外其他的连接节点中最多一个子树可以不放在点集中,且该子树只能为单链状的。每个点都记录一个序号,初始序号即为该点的序号。每次如果扫到叶子节点了,若还不能确定是否将其放入点集,则把这个节点序号传给父节点,返回。如果父节点已经存了其他子节点,则该叶子节点所存的序号放入点集,只要一个点的所有子树只有一个没放入点集则该点已经合法,遍历结束,返回上层节点
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const int maxn = 1e5 + 50;
#define INF 0xffffff
int t, n;
vector<int> mm[maxn];
bool vis[maxn];
int res[maxn];
int ind[maxn];
bool color[maxn];
int ans[maxn], cnt=0;
bool dfs(int k, int fa)
{
int ne;
bool f = 0;
for(int i=0;i<mm[k].size();i++)
{
ne = mm[k][i];
if(ne==fa || vis[ne])continue;
if(!dfs(ne,k))
{
if(res[k]==k)
res[k] = res[ne];
else
{
color[res[ne]] = 1;
ans[cnt++] = res[ne];
f = 1;
}
}
else
f = 1;
}
return f;
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(ind,0,sizeof(ind));
for(int i=1;i<=n;i++)
{
mm[i].clear();
}
int maxs = 0;
for(int i=0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
mm[u].push_back(v);
mm[v].push_back(u);
ind[u]++,ind[v]++;
maxs = max(maxs,ind[u]);
maxs = max(maxs,ind[v]);
}
cnt = 0;
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
for(int i=1;i<=n;i++)
res[i] = i;
for(int i=1;i<=n;i++)
{
if(ind[i]==maxs)
{
dfs(i,0);
break;
}
}
if(!cnt)
{
ans[cnt++] = 1;
}
printf("%d\n",cnt);
for(int i=0;i<cnt-1;i++)
{
printf("%d ",ans[i]);
}
if(cnt)
printf("%d\n",ans[cnt-1]);
}
}