CF1041E Tree Reconstruction

该博客探讨了一种非链状结构的树形问题,涉及删除边后形成的连通块最大节点编号的判断。核心思路在于识别树中最大编号节点必须为根节点,以及根据节点出现次数构建满足条件的树。通过分析节点出现次数,将节点分为叶子节点和中间节点,最终构造出满足条件的树并输出边的连接。
摘要由CSDN通过智能技术生成

提供一种不是链的做法

题意:

给定 一棵树中每条边被删去后,形成的两个连通块中两个编号最大的点的编号,问 满足条件的树存不存在。若存在,输出 YES ,并给出方案,否则输出 NO 。

思路:

首先,我们可以很明显地看到,无论砍掉树上哪一条边,其中一个连通块内编号最大的树一定是 N N N。若不满足这一条件,可直接判无解。

我们把最后答案里的树想象成一个类似菊花图的样子,如下图所示:

而这棵树的根一定是n。

然后,观察输入数据中每个数(除 N N N 外 )的出现次数,将其分为以下两类:

  • t o t = 0 tot=0 tot=0 ,即没有出现,此时它应该属于一个编号比它大的叶子节点。

  • t o t > 0 tot>0 tot>0 , 即出现过了,则它就是叶子节点,且它到 N N N 的路径上(不包括 N N N 和它自己)有且仅有 t o t − 1 tot-1 tot1 个点

若不符合,则无解。

按以上操作不断更新即可。

CODE:

#include<bits/stdc++.h>
using namespace std;
#define NO printf("NO\n")
#define YES printf("YES\n")
int n,edgenum,tot_l,tot_m,tot[1005],leaves[1005],middle[1005];
struct node{
	int x,y;
}b[1005];
void add(int u,int v){
	edgenum++;
	b[edgenum].x=u;
	b[edgenum].y=v;
}
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++){
		scanf("%d%d",&x,&y);
		if(x>y) swap(x,y);
		if(y!=n||x==y){NO;return 0;}
		tot[x]++;
	}
	for(int i=1;i<n;i++){
		if(tot[i]>0) leaves[++tot_l]=i;
		if(tot[i]==0) middle[++tot_m]=i;
	}
	sort(leaves+1,leaves+tot_l+1);
	sort(middle+1,middle+tot_m+1);
	int _top=1;
	for(int i=1;i<=tot_l;i++){
		if(tot[leaves[i]]==1){
			add(leaves[i],n);
			tot[leaves[i]]--;
			continue;
		}
		tot[leaves[i]]--;
		int u=leaves[i];
		while(tot[leaves[i]]){
			bool get=true;
			if(middle[_top]<=leaves[i]){
				add(u,middle[_top]);
				u=middle[_top];
				_top++;tot[leaves[i]]--;
				get=false;
			}
			if(get){NO;return 0;}
		}
		add(n,u);
	}
	YES;
	for(int i=1;i<n;i++) printf("%d %d\n",b[i].x,b[i].y);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值