#构造#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;
}
posted @ 2020-10-19 21:45  lemondinosaur  阅读(205)  评论(0编辑  收藏  举报