Codeforces 1003E
题意:要构造一棵$n$个点的直径为$d$,并且每个点度数必须小于等于$k$的树
先将直径连起来,然后从中间开始在直径上拓展树,子树上每个点到直径两端都不可以超过$d$,并且要满足每个点度数必须小于等于$k$。用 DFS 完成拓展子树。算是一个细节题,注意处处当前节点如果达到$n$就马上退出
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
int n, d, k, sz, tot;
pair<int, int> ans[500000 + 5];
void dfs(int curlen, int kidlen, int curu) {
if (curlen == d) return ;
for (int i = 1; i <= kidlen; i++) {
sz++;
ans[++tot].first = curu, ans[tot].second = sz;
if (sz >= n) {
cout << "YES\n";
for (int i = 1; i <= tot; i++) printf("%d %d\n", ans[i].first, ans[i].second);
exit(0);
}
dfs(curlen + 1, k - 1, sz);
}
}
void clean() {}
int solve() {
clean();
cin >> n >> d >> k;
if (n < d + 1) return cout << "NO", 0;
if (k == 1 && n != 2 && d != 1) return cout << "NO", 0;
tot = 0, sz = 1;
for (int i = 1; i < d + 1; i++) ans[++tot].first = sz, sz++, ans[tot].second = sz;
if (sz >= n) {
cout << "YES\n";
for (int i = 1; i <= tot; i++) printf("%d %d\n", ans[i].first, ans[i].second);
exit(0);
}
int l = (d + 1 + 1) / 2, r = (d + 1) / 2 + 1;
while (1) {
if (l == 1 || r == d + 1) break;
dfs(max(l - 1, d + 1 - l), k - 2, l);
if (l != r) dfs(max(l - 1, d + 1 - l), k - 2, r);
l--, r++;
}
if (sz < n) return cout << "NO", 0; else {
cout << "YES\n";
for (int i = 1; i <= tot; i++) printf("%d %d\n", ans[i].first, ans[i].second);
}
return 0;
}
int main() {
solve();
return 0;
}