Codeforces 1041E Tree Reconstruction

题面在这里

题意:给定n-1个点对,分别表示树上一条边删去后两个联通块的编号最大值,构造一棵满足上述点对的树

首先注意到\(n\)一定在每个给出的点对中出现过

那么可以把\(n\)作为根,每个点对剩下那个数字就是一个子树的最大值

显然\(n-1\)出现次数就是深度

考虑\(n-2\)出现了\(k\)次,其对应着一条长为\(k\)的链,可以接在任意位置,就放在\(n\)上好了

其他同理,最后把所有没出现过的节点填到链上即可

注意只能填到大编号对应的链上,如果找不到就是无解

示例程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=1005;
int n,X[maxn],Y[maxn],dep[maxn],lst[maxn],len;
pair<int,int> ans[maxn];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&X[i],&Y[i]);
dep[X[i]]++;dep[Y[i]]++;
}
if (dep[n]!=n-1) return puts("NO"),0;
for (int i=1;i<=n;i++)
if (dep[i]) lst[i]=n;
for (int i=1;i<=n;i++)
if (dep[i]==0){
int j;
for (j=i+1;j<n;j++)
if (dep[j]>1) break;
if (j>=n) return puts("NO"),0;
ans[++len]=make_pair(lst[j],i);
dep[j]--;lst[j]=i;
if (!dep[j]) ans[++len]=make_pair(i,n);
}
for (int i=1;i<=n;i++)
if (dep[i]==1) ans[++len]=make_pair(lst[i],i);
puts("YES");
for (int i=1;i<n;i++) printf("%d %d\n",ans[i].first,ans[i].second);
return 0;
}