(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
题意:传送门
原题目描述在最下面。
给你n, k, d。问是否能构造出一颗树,其有n个节点,直径为k,每个点的度数不超过d。若能,则输出YES
并输出任意符合条件的解,反之输出NO
。
思路:
我的写法是先特判能否构造出一条直径来,若不能则直接输出NO
。构造出了直径之后,就枚举这条直径上的点,进行dfs。
控制直径:
控制直径上每个节点能往下延伸的长度。长度 = min(dep[i] - 1, k + 1 - dep[i])
。
控制度数:
还要控制每个节点还能增加的分叉数量。数量 = d - du[i]
搜索的过程中记录一共使用了多少个节点,如果已经有n个节点了就返回。如果始终不能达到n个节点就输出NO
,反之输出任意解。
AC代码:
#include<bits/stdc++.h>
#define mk make_pair
using namespace std;
typedef long long LL;
const int inf=2e9+1e8+1234;
const LL linf=8e18+9e17;
const int N = 4e5+7;
const int mod = 998244353;
int n, k, d, tot;//直径不超过k,每个度数不超过d
int du[N], dep[N];
vector<pair<int, int> >ans;
void dfs(int u, int remain){
if(remain == 0 || du[u] >= d || tot == n)return;
int _du = du[u];
//printf("u = %d, remain = %d, du = %d, dep = %d\n", u, remain, du[u], dep[u]);
for(int i = 0; i < d - _du; ++i){
ans.push_back(mk(u, ++tot));
dep[tot] = dep[u] + 1;
du[tot]++;du[u]++;
if(tot>=n)return;
dfs(tot, remain - 1);
if(tot>=n)return;
}
}
int main(int argc, char const *argv[]){
while(~scanf("%d%d%d", &n, &k, &d)){
if(k>=n){//特判
printf("NO\n");
continue;
}
memset(du, 0, sizeof(du));
memset(dep, 0, sizeof(dep));
ans.clear();
du[0] = du[1] = -1;
for(int i = 1; i <= k + 1; ++i){
du[i]++;du[i-1]++;
dep[i] = i;
if(i>1)ans.push_back(mk(i - 1, i));
}
tot = k + 1;
for(int i = 1; i <= k + 1; ++i){
dfs(i, min(dep[i] - 1, k + 1 - dep[i]));
}
if(tot != n || (k > 1 && d == 1)){
printf("NO\n");
}else{
printf("YES\n");
for(auto x: ans){
printf("%d %d\n", x.first, x.second);
}
}
}
return 0;
}