提供一种不是链的做法
题意:
给定 一棵树中每条边被删去后,形成的两个连通块中两个编号最大的点的编号,问 满足条件的树存不存在。若存在,输出 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 tot−1 个点。
若不符合,则无解。
按以上操作不断更新即可。
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;
}