#构造#B 连通子图
题目
给定正整数\(k\),构造一棵树,使得包含了\(1\)号点的连通子图个数恰好为\(k\)。
连通子图就是点集的一个子集(可以为全集),使得该点集中任意两个点均可以经过该点集中的点相互到达。
分析
显然可以得到\(f[x]=\prod_{y\in son_x} (f[y]+1)\)
同时树的大小不超过60说明与log级别的算法有关,
如果将\(x\)多一个子节点那么个数乘2,如果增加父节点个数加1,
那可以通过这种方式构造
代码
#include <cstdio>
#include <cstring>
#define rr register
using namespace std;
struct node {
int y, next;
} e[71];
int n, root, tot, k, dfn[71], st, as[71];
inline void dfs(int x) {
dfn[x] = ++tot;
for (rr int i = as[x]; i; i = e[i].next) dfs(e[i].y);
}
signed main() {
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
while (scanf("%d", &n) == 1) {
root = tot = k = 1;
memset(as, 0, sizeof(as));
for (st = 29; ~st; --st)
if ((n >> st) & 1)
break;
for (rr int i = st - 1; ~i; --i) {
e[++k] = (node){ ++tot, as[root] }, as[root] = k;
if ((n >> i) & 1)
e[++k] = (node){ root, as[++tot] }, as[root = tot] = k;
}
tot = 0, dfs(root), printf("%d\n", tot);
for (rr int i = 1; i <= tot; ++i)
for (rr int j = as[i]; j; j = e[j].next) printf("%d %d\n", dfn[i], dfn[e[j].y]);
}
return 0;
}