2020牛客多校第二场 C-Cover the Tree

Cover the Tree

链接

题意

给出n,表示有n个树的节点,随后n-1行给出树的边。
答案中a b表示节点a连到节点b,题目要求在连的边最少情况下所连边覆盖所有点。

思路

先从一个至少有两个子节点的点作为根节点,求出叶子节点的dfs序,然后把所有叶子节点分成两块,从两块左边开始分别两两匹配,如果叶子节点个数为奇,则最后一个叶子节点连着根节点。
注意本来n=2的时候是要特判的,即使是标程也是有错误的,可能数据根本没有n=2。

代码

#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define PII pair<int,int>
#define first fi
#define second se

int T;
int qmi(int a,int b){
	int res=1;
	while(b){
//		if(b&1)res=res*a%mod;
		b>>=1;
//		a=a*a%mod;
	}
	return res;
}

int read(int &x){
	x=0;
	int f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
const int N=2e5+10; 
vector<int>v[N];
bool vis[N];
vector<int>son;
void build(int u){
	vis[u]=1;
	if(v[u].size()==1){
		son.push_back(u);
		return;
	}
	for(int item:v[u]){
		if(!vis[item]){
			build(item);
		}
	}
}
void solve(){
	int n;
	read(n);
	for(int i=1;i<=n-1;i++){
		int a,b;
		read(a);
		read(b);
		v[a].push_back(b);
		v[b].push_back(a);
	} 
	int k;
	for(k=1;k<=n;k++){
		if(v[k].size()>1){
			build(k);
			break;
		}
	}/*
	int cnt=son.size(),rt=k;
	int m = (cnt + 1) / 2;
	printf("%d\n", m);
	for (int i = 1; i * 2 <= cnt; i ++)
		printf("%d %d\n", son[i + m-1], son[i-1]);
	if (cnt & 1)
		printf("%d %d\n", rt, son[m-1]);
	*/

	int ans;
	if(son.size()&1){
		int mid=(son.size()+1)>>1;
		ans=mid;
		printf("%d\n",ans);
		for(int i=1;i*2<=son.size();i++){
			printf("%d %d\n",son[i-1],son[i+mid-1]);
		}
		printf("%d %d\n",k,son[mid-1]);
	} else {
		int mid=son.size()>>1;
		ans=mid;
		printf("%d\n",ans);
		for(int i=1;i*2<=son.size();i++){
			printf("%d %d\n",son[i-1],son[i+mid-1]);
		}
	}

}

int main(){
//	read(T);
	T=1;
	while(T--){
		solve();
	}
	return 0;
}
/*
5
1 3
1 2
2 4
2 5

5
1 2 
2 4
2 5
2 6

4
1 2
2 3
3 4

3
1 2
1 3
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值