92. 递归实现指数型枚举 - AcWing题库
70. 爬楼梯 - 力扣(LeetCode)
92. 递归实现指数型枚举 - AcWing题库
从 1∼n这 n 个整数中随机选取任意多个,输出所有可能的选择方案。
输入格式
输入一个整数 n。
输出格式
每行输出一种方案。
同一行内的数必须升序排列,相邻两个数用恰好 11 个空格隔开。
对于没有选任何数的方案,输出空行。
本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。
数据范围
1≤n≤15
输入样例:
3
输出样例:
3
2
2 3
1
1 3
1 2
1 2 3
code:
#include <stdio.h>
#include <stdlib.h>
#define N 20
int n;
int st[N] = {};//开一个状态数组 0表示空着 1表示选了 2表示不选
void dfs(int x){
if(x > n){
for(int i = 1 ; i <= n ; i++){
if(st[i] == 1){
printf("%d ", i);
}
}
printf("\n");
return;
}
//选择
st[x] = 1;
dfs(x + 1);
st[x] = 0;
//不选
st[x] = 2;
dfs(x + 1);
st[x] = 0;
}
int main()
{
scanf("%d", &n);
dfs(1);
return 0;
}
程序概览
这个程序定义了一个递归函数 dfs
(深度优先搜索),用于生成从 1
到 n
的所有子集。在 dfs
函数中,我们探索了两种情况:选择当前元素(将其状态设置为 1
)和不选择当前元素(将其状态设置为 2)。接下来,我们详细分析这个函数的行为。
执行过程细节
-
调用
dfs(1)
:-
首先,检查
x > n
的条件。对于x=1
和n=3
,这个条件为假,所以不执行 if 语句块内的代码。 -
接下来,设置
st[1] = 1
。 -
紧接着,调用
dfs(2)
。在这一点上,程序的执行流进入dfs(2)
,开始处理dfs(2)
内的所有逻辑。
-
-
执行
dfs(2)
中的代码:- 程序会在
dfs(2)
完成其全部逻辑(包括它自己的递归调用等)后,才会返回到dfs(1)
中dfs(2)
调用之后的代码行st[x] = 0
。
- 程序会在
-
回到
dfs(1)
继续执行:-
完成
dfs(2)
后,st[1]
被设置为0
。 -
然后,设置
st[1] = 2
,并再次调用dfs(2)
。同样地,程序将进入dfs(2)
并处理所有相关逻辑。 -
dfs(2)
完成后继续执行st[1] = 0。
-
回溯的执行过程
具体例子分析(假设 n=3
)
-
初始调用
dfs(1)
:- 选择
1
(设置st[1] = 1
),然后递归调用dfs(2)
。
- 选择
-
在
dfs(2)
中:- 选择
2
(设置st[2] = 1
),然后递归调用dfs(3)
。
- 选择
-
在
dfs(3)
中:- 选择
3
(设置st[3] = 1
),然后递归调用dfs(4)
。
- 选择
-
达到结束条件,开始输出(
dfs(4)
发现x > n
):-
输出
{1, 2, 3}
。 -
回溯到
dfs(3)
:撤销选择3
(设置st[3] = 0
),尝试不选择3
,再次调用dfs(4)
。
-
-
再次达到临界条件:
-
输出
{1, 2}
。 -
回溯到
dfs(2)
:撤销选择2
(设置st[2] = 0
),尝试不选择2
,调用dfs(3)
。
-
-
继续在
dfs(3)
中操作:-
之前已经尝试了选择
3
和不选择3
的情况,输出{1, 3}
和{1}
。 -
回溯到
dfs(1)
:撤销选择1
(设置st[1] = 0
),尝试不选择1
,调用dfs(2)
。
-
-
对于
dfs(2)
和dfs(3)
,再次执行选择和不选择的操作:- 生成并输出剩余的子集
{2, 3}
,{2}
, 和{3}
,{}
。
- 生成并输出剩余的子集
树状图理解
dfs(1)
/ \
/ \
[1]选1 (选取1) [1]不选1 (不选取1)
/ \ / \
/ \ / \
dfs(2, {1}) dfs(2, {}) dfs(2, {1}) dfs(2, {})
/ \ / \ / \ / \
/ \ / \ / \ / \
[2]选2 [2]不选2 [2]选2 [2]不选2 [2]选2 [2]不选2 [2]选2 [2]不选2
/ \ / \ / \ / \ / \ / \ / \
dfs(3,{1,2}) ... ... ... ... ... ... ... ... ... ... ...
/ \
/ \
[3]选3 [3]不选3
每次都有两个选项,选择和不选择。这里用数组st记录状态,每个位置如果是0表示空着,1表示选择,2表示不选
70. 爬楼梯 - 力扣(LeetCode)
递推
int nums[50];
int climbStairs(int n){
nums[1] = 1;
nums[2] = 2;
for(int i = 3 ; i <= n ; i++){
nums[i] = nums[i - 1] + nums[i - 2];
}
return nums[n];
}
递归
nums[5]
/ \
nums[4] nums[3]
/ \ / \
nums[3] nums[2] nums[2] nums[1]
/ \
nums[2] nums[1]