发布于 

Tree Constructing

Tree Constructing

CF 494 E

这次是div3的题目,本身没有涉及到什么复杂的算法,可以说就是一道模拟题。不过细节还是很多的,需要注意。比赛时因为漏掉了一个细节结果比赛后被hack了,否则这次div3能排到一百多名(〒▽〒)。。。。

题解

题目要求给定顶点数n,直径d,和最大度数k,是否有这样的数存在。存在的话输出这棵树的所有边。

首先,这里的nd都是必须正好满足的,而k则是要求树最大度数小于等于k即可。所以,在这里,我们应该先从d入手。

很明显,我们可以首先尝试构建一个最长边,它总共包含d+1个点。所以,若$ n d $,就可以直接输出"NO"

而当我们构建最长边时,若\(d+1==1\),则必须满足\(k\ge0\);若$ d+1==2\(,则必须满足\)k\(;若\)d+1\(,则必须满足\) k $。所以若以上条件不满,我们也可以输出"NO"

在最长边构建完成之后,我们便可以开始构建其他的边了。很明显,其他的边都是由最长边上的点为根节点延伸出来的,也就是说,其他的边集构成了一个根节点为最长边上的点的若干个子树。所以说,我们在最长边上一直生成子树,就能够形成一个满足最终条件的树。

当然,也存在不满足条件的情况。若我们已经构建了所有满足情况的子树之后,结点数还是小于n的话,说明无法构建,此时应该输出"NO"

还有,我们该如何生成一个符合条件的子树呢?我们可以使用一个递归的建树函数,分别传入该点的序号,该点剩余的度数和该点向下还能够建树的深度。这样的话当深度为0是直接返回,从而使我们生成的子树不会令最长边变长。

代码

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

#include <iostream>

using namespace std;

int n,d,k;
int cur;

int ans[400100][2];
int num = 0;

void build(int x,int t,int kk)
{
trueif (t==0)
truetruereturn;

trueif (cur>n)
truetruereturn;

truefor (int i = 0; i<kk; i++)
true{
truetrueans[num][0] = x;
truetrueans[num][1] = cur;
truetruecur ++;
truetruenum ++;

truetrueif (cur > n)
truetruetruereturn;

truetruebuild(cur-1,t-1,k-1);

truetrueif (cur > n)
truetruetruereturn;
true}
}

int main()
{

truecin >> n >> d >> k;
trued++;

trueif (n < d || (d>2 && k==1) )
true{
truetruecout << "NO";
truetruereturn 0;
true}
truefor (int i = 1; i<d; i++)
true{
truetrueans[num][0] = i;
truetrueans[num][1] = i+1;
truetruenum++;
true}
truecur = d+1;

truefor (int i = 1; i<=d; i++)
truetruebuild(i,min(i-1,d-i),k-2);

true//cout << "! " << num << endl;
trueif (num!=n-1)
truetruecout << "NO" << endl;
trueelse{
truetruecout << "YES" << endl;
truetruefor (int i = 0; i<num; i++)
truetruetruecout << ans[i][0] << " " << ans[i][1] << endl;
true}
}


本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 [@Songer](https://blog.songer.xyz/) 创建,使用 Stellar 作为主题。