Cover the Tree

题目描述

Given an unrooted tree, you should choose the minimum number of chains that all edges in the tree are covered by at least one chain. Print the minimum number and one solution. If there are multiple solutions, print any of them.

输入

The first line contains one integer n~(1\leq n \leq 2\times10^5)n (1≤n≤2×10
5
), denoting the size of the tree.
Following {n-1}n−1 lines each contains two integers u,v~(1\leq u < v \leq n)u,v (1≤u<v≤n), denoting an edge in the tree.
It’s guaranteed that the given graph forms a tree.

输出

The first line contains one integer {k}k, denoting the minimum number of chains to cover all edges.
Following {k}k lines each contains two integers u,v~(1\leq u,v \leq n)u,v (1≤u,v≤n), denoting a chain you have chosen. Here {u = v}u=v is permitted, which covers no edge.

样例输入

5
1 2
1 3
2 4
2 5

样例输出

2
2 3
4 5

题目大意

给定一棵有k个节点的无根树,要求用链覆盖所有边,求出最少需要几条链以及每条链的起点终点。

分析

这题比较简单,但要注意思维漏洞。
不难得出当起点终点为叶子节点时最优,问题是如何安排哪两个叶子节点组成同一条链的起点和终点。

一个简单思路

很容易简单地认为随意两个组成一条链即可,但也很容易举出反例。

一个更进一步的思路

于是想到用DFS(根节点?只要度数不是1就可以随便选)来把相隔最远的节点构成链,如图:
在这里插入图片描述
于是提交,只有80分,为什么呢?原来还有坑人的反例不要把出题人想得太美好
在这里插入图片描述
很明显,边(1,5)被略过了。

一个完美的思路

那么我们就选从中间一分为二后最靠同一边的叶子节点来连线,可以发现这时链是能完美覆盖的:
在这里插入图片描述

代码
#include<bits/stdc++.h>

using namespace std;

const int MAXN=2e5+100;
int k,ans,u,v,root=-1,flag=1,a[MAXN],du[MAXN];
vector<int> vec[MAXN];

void DFS(int x,int fx)
{
	if(du[x]==1)
	{
		a[++ans]=x;return; 
	}
	for(int i=0;i<vec[x].size();i++)
	{
		int now=vec[x][i];
		if(now==fx) continue;
		DFS(now,x);
	}
}

int main()
{
    scanf("%d",&k);
    for(int i=1;i<k;i++)
	{
        scanf("%d%d",&u,&v);
        du[u]++;du[v]++;
        if(du[u]>=2&&flag) root=u,flag=0;
		if(du[v]>=2&&flag) root=v,flag=0;
        vec[u].push_back(v);vec[v].push_back(u);
    }
    if(root==-1)
    {
    	printf("1\n%d %d",u,v);return 0;
	}
    DFS(root,-1e9);
    printf("%d\n",(ans+1)/2);
    for(int i=1;i<=ans/2;i++) printf("%d %d\n",a[i],a[(ans+1)/2+i]);
	if(ans&1) printf("%d %d\n",root,a[ans/2+1]);
}

-------原创文章,仅供参考

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值