[算法][递归/深搜]递归实现指数型枚举
递归实现指数型枚举
从 1∼n这 n个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 n
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 1
个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤15
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
解题思路
思路一
位掩码法
# 输入整数n
n = int(input())
# 遍历所有可能的子集掩码,每个掩码对应一个二进制数,范围是0到2^n - 1
for mask in range(2 ** n):
subset = [] # 初始化当前子集
# 遍历每一位,检查是否选中该位对应的数字
for i in range(n):
# 1 << i 生成一个二进制数,仅在第i位为1(从0开始计数)
# mask & (1 << i) 检查mask的第i位是否为1
# 如果为真,说明当前数字(i+1)被选中,加入子集
if mask & (1 << i):
subset.append(str(i + 1)) # 注意数字是i+1,因为i从0开始
# 将子集中的元素用空格连接成字符串输出,空子集时输出空行
print(' '.join(subset))
代码逻辑解释:
- 每个子集可以唯一对应一个二进制数(掩码),每一位的0/1表示对应数字是否被选中。
- 例如,n=3时,掩码5(二进制101)对应子集{1,3}。
- 遍历所有可能的掩码(0到2^n-1),每个掩码生成一个子集。
- 对于每个掩码,通过位运算检查每一位是否为1:
- 外层循环遍历所有可能的子集,内层循环遍历每个数字的位置。
- 由于i从0到n-1递增,对应的数字是1到n,按顺序检查是否选中,保证子集元素升序排列。
- 输出时,将子集元素转换为字符串并用空格分隔,空子集自动处理为有效空行。
该方法的时间复杂度为O(n * 2^n),适用于n≤15的情况,完全满足题目要求。
个人理解:
进行 0 到 2^n 的遍历 (即每个数字的二进制码)
e.g: n = 3
for mask in range(2**n): 即是从0到8遍历
for i in range(n): 即是从0到4又遍历一遍
详细说说 1 << i
是 1 向左推出i位
mask在此处已自动变成二进制 0<= i <= 2 0<=mask <=8
mask & (1 << i)是指检查mask的第i位是否为1
当mask = 0 时:
|i |1<<i |mask & (1<<i) |
|0 |1 |0 |
|1 |10 |0 |
|2 |100 |0 |
subset = []
当mask = 1(1)时
|i |1<<i |mask & (1<<i) |
|0 |1 |1 |
|1 |10 |0 |
|2 |100 |0 |
subset = [1]
当mask = 2(10)时
|i |1<<i |mask & (1<<i) |
|0 |1 |0 |
|1 |10 |1 |
|2 |100 | |
subset = [2]
当mask = 3(11)时
|i |1<<i |mask & (1<<i) |
|0 |1 |1 |
|1 |10 |1 |
|2 |100 |0 |
subset = [1 2]
当mask = 4(100)时
|i |1<<i |mask & (1<<i) |
|0 |1 |0 |
|1 |10 |0 |
|2 |100 |1 |
subset = [3]
当mask = 5(101)时
|i |1<<i |mask & (1<<i) |
|0 |1 |1 |
|1 |10 |0 |
|2 |100 |1 |
subset = [1 3]
当mask = 6(110)时
|i |1<<i |mask & (1<<i) |
|0 |1 |0 |
|1 |10 |1 |
|2 |100 |1 |
subset = [2 3]
当mask = 7(111)时
|i |1<<i |mask & (1<<i) |
|0 |1 |1 |
|1 |10 |1 |
|2 |100 |1 |
subset = [1 2 3]
# 将子集中的元素用空格连接成字符串输出,空子集时输出空行
print(' '.join(subset))
思路二
DFS+递归
lt = [0] * 16
# dfs需要考虑返回情况
def dfs(u):
if u > n: # n为输入的值(递归深度)
# 满足条件的情况
print() # 换行
for i in range(1,n+1): # [1~n]
if lt[i]: # 不为0
print(i,end=" ")
return
else:
lt[u] = 1 #为1的情况遍历
dfs(u+1)
lt[u] = 0 #为0的情况遍历
dfs(u+1)
n = int(input())
dfs(1)
递归树
若n=2
dfs(1)
├─ lt[1]=1 → dfs(2)
│ ├─ lt[2]=1 → dfs(3) → 输出1 2
│ └─ lt[2]=0 → dfs(3) → 输出1
└─ lt[1]=0 → dfs(2)
├─ lt[2]=1 → dfs(3) → 输出2
└─ lt[2]=0 → dfs(3) → 输出空集

浙公网安备 33010602011771号