题意
给定一颗无根树,任意两点可形成一条链,找出最少的链使其并集为全部的边。输出最少点对数并写出点对
- 链接:Cover the Tree
- 范围:1≤n≤2×105 1≤u<v≤n
- 输入
5
1 2
1 3
2 4
2 5
- 输出
2
2 3
4 5
解题思路
简单思路:以度不为1的点作为根节点,每次将其与叶子结点链接,即可把所有边覆盖,答案即为度为1的叶子结点数,显然不是题目所要求的最小解- 优化:将根节点作为中间结点,链接左右两端的根结点,则答案为(叶子节点数+1)/2 向下取整
代码
#include<stdio.h>
int const N=2e5+5;
int n,u,v,d[N],head[N],ans[N],root,cnt,tot;
struct node{
int to,next;
}e[N*2];
void add(int u,int v)
{
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
d[u]++;
}
void dfs(int son,int fa)
{
if(d[son]==1) ans[++tot]=son;
for(int i=head[son];i;i=e[i].next)
{
if(e[i].to==fa)continue;
dfs(e[i].to,son);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
if(n==1) printf("0\n");
else if(n==2) printf("1\n1 2\n");//特判
else{
for(int i=1;i<=n;i++)
{
if(d[i]!=1)
{
root=i;break;
}
}
//找任意非叶子结点作为根节点
dfs(root,root);
int sum=(tot+1)/2;
printf("%d\n",sum);
if(tot%2==1) ans[++tot]=root;
for(int i=1;i<=sum;i++)
printf("%d %d\n",ans[i],ans[i+sum]);
}
return 0;
}