CF1041E Tree Reconstruction

看上去非常不可做的题

建议手玩

首先考虑无解的情况,考虑树断开一条边之后会怎么样

显然 n 一定是其中一部分的答案,另一部分的答案不确定

所以当 存在 i 使得 ai ≠ n 且 bi ≠ n 时,就没有合法的答案

似乎没有什么了,继续考虑如何构造

当一个点作为 ai 出现过多次时(假设有 x 次),那么它到 n 号点路径上就至少要有 x 条边,且这条路径上的点编号 <= ai

发现按上述条件构造的话,总觉得会被卡掉,就大概是 ai 到 n 路径上边数多于 x

想一想好像这样构造确实是没有问题的,不过 “至少” 这个条件就变成了 “恰好”

所以我们又发现了一个无解的情况,那就是当一个点作为 ai 出现的次数超过它的编号大小的话,也是会无解的

这样这题就可做了


 代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cstdio>
using namespace std;

const int MAXN = 1005;

int n;
int a[MAXN], b[MAXN], dst[MAXN];
bool set[MAXN];

inline void make_path(int x) {
	int lst = x, rem = dst[x];
	for(int i = 1; i < n; ++i) {
		if(set[i]) {
			if(rem != 1) {
				set[i] = false;
				printf("%d %d\n", lst, i);
				lst = i;
				--rem;
			}
		}
		if(rem == 1) {
			printf("%d %d\n", lst, n);
			return;
		}
	}
	return;
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) set[i] = true;
	for(int i = 1; i < n; ++i) {
		scanf("%d%d", &a[i], &b[i]);
		++dst[a[i]];
		set[a[i]] = false;
		if(b[i] != n) {
			puts("NO");
			return 0;
		}
	}
	sort(a + 1, a + n);
	for(int i = 1; i < n; ++i) {
		if(i > a[i]) {
			puts("NO");
			return 0;
		}
	}
	puts("YES");
	for(int i = 1; i <= n; ++i) {
		if(!dst[i]) continue;
		if(dst[i] == 1) {
			printf("%d %d\n", i, n);
		} else {
			make_path(i);
		}
	}
	return 0;
}

  

posted @ 2018-09-19 23:25  EvalonXing  阅读(188)  评论(0编辑  收藏  举报