递归实现指数型枚举

GitHub跳转原题关系图返回列表

每个整数「选 / 不选」构成一棵深度 n 的满二叉决策树,递归遍历即得全部 2^n 个子集;升序天然成立。

OJ: roj

题目 ID: 3006

难度:入门

标签:递归搜索位运算python

创建: 2026-10-01 09:37

更新: 2026-10-06 10:57

题目描述

给定 nn(1≤n≤151 \le n \le 15),从 1∼n1 \sim n 任选若干个数,每行输出一种方案(升序、单空格分隔,不选则空行),行序任意。

思路

把每个数看成选/不选决策,nn 个数构成满二叉决策树,2n2^n 个叶子即全部子集;先递归不选再递归选,路径下标天然升序。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-10-01 09:38
# update_at: 2026-10-01 09:38

import sys
from collections.abc import Iterator


def schemes(n: int, chosen: int = 0, nxt: int = 1) -> Iterator[list[int]]:
    """递归枚举下标 nxt 选或不选;chosen 第 i-1 位为 1 表示整数 i 已选。"""
    if nxt > n:
        # 叶子:把位掩码还原成升序序列,没有选中任何数时还原成空列表
        yield [i for i in range(1, n + 1) if chosen >> (i - 1) & 1]
        return
    yield from schemes(n, chosen, nxt + 1)                     # 不选 nxt
    yield from schemes(n, chosen | 1 << (nxt - 1), nxt + 1)    # 选 nxt


def solve() -> None:
    n = int(sys.stdin.buffer.read())  # 题面只有一个整数 n
    print("\n".join(" ".join(map(str, choice)) for choice in schemes(n)))


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-06 10:53
 * update_at: 2026-10-06 10:53
 */
#include <cstdio>
using namespace std;

typedef long long ll;

int n;
int chosen[20]; // chosen[i] = 1 表示整数 i 已被选中

// 递归枚举第 u 个数选或不选
void dfs(int u) {
    if (u > n) {
        // 叶子:按升序输出已选中的数
        bool first = true;
        for (int i = 1; i <= n; ++i) {
            if (chosen[i]) {
                if (!first) printf(" ");
                printf("%d", i);
                first = false;
            }
        }
        printf("\n");
        return;
    }
    // 不选 u
    chosen[u] = 0;
    dfs(u + 1);
    // 选 u
    chosen[u] = 1;
    dfs(u + 1);
}

int main() {
    scanf("%d", &n);
    dfs(1);
    return 0;
}