递归与递推——递归实现指数型枚举

这篇博客介绍了一个C++代码实现,用于从1到n的整数中使用深度优先搜索(DFS)生成所有可能的选择组合。代码通过递归方式实现,确保每个选择方案按升序排列并用空格隔开。输出包括空行以表示没有选择任何数字的方案。该程序适用于小规模数据,例如n≤15的情况。

从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。

输入格式

输入一个整数 n。

输出格式

每行输出一种方案。

同一行内的数必须升序排列,相邻两个数用恰好 11 个空格隔开。

对于没有选任何数的方案,输出空行。

本题有自定义校验器(SPJ),各行(不同方案)之间的顺序任意。

数据范围

1≤n≤15,1≤n≤15

输入样例:

3

输出样例:

3
2
2 3
1
1 3
1 2
1 2 3

代码实现:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;//输入
const int N=16;//全局变量
int s[N];//用来记录这个位置选不选这个数,0表示未选,1表示选了,2表示不选
void dfs(int u)//深度优先搜索
{
    if(u>n)//出口,当u已经大于n的时候,说明n个位置的数已经被填满了
    {
        for(int i=1;i<=n;i++)
        {
            if(s[i]==1)
            {
                cout<<i<<" ";
            }
        }
        cout<<endl;
        return ;
    }
   
    s[u]=1;//说明这个位置选
    dfs(u+1);
   //这中间其实应该有一个复原操作,但是立马又被赋值了,就省略掉
    s[u]=2;//这个位置的数不选
    dfs(u+1);
    s[u]=0;
​
}
int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

采取深度优先搜索的时候,就是最开始就一条道走到黑,如图就是最左侧那套路线

当碰壁之后,就会进行回溯

注意,每次溯回都会执行当前栈中的程序

也就是第一个dfs(u+1)执行完毕后溯回到这一层,就会执行下面的dfs(u+1)

也就是路线4,回到上一层后就会继续执行路线5,然后回溯,走6,接着回溯,走7,依次类推

<think>嗯,用户之前让我写一篇关于递推递归在多项式枚举中的简单运用的演讲稿,现在他们又提出了一个更详细的问题,询问递推递归在多项式枚举中的定义、底层逻辑及简单应用。需要结合之前的回答和提供的引用内容来综合解答。 首先,我得明确用户的需求。他们可能是在准备算法相关的学习或演讲,需要深入理解递推递归枚举问题中的应用,特别是多项式的情况。用户已经看过之前的演讲稿,但需要更详细的知识点,包括定义、底层逻辑和应用实例。 接下来要参考用户提供的引用内容。引用[1]提到递推递归是遍历状态空间的两种方式,状态空间是问题的可能情况集合。引用[2]和[3]区分了多项式枚举(如n^k)使用循环或递推,而指数递归。同时,递归需要处理还原现场的问题。引用[5]中的例子涉及分治和坐标变换,这可能作为应用案例。 需要将递推递归的定义分开解释,底层逻辑部分要提到递推的状态转移和循环迭代,递归的栈和回溯。应用方面,递推适合组合数计算,递归适合排列生成,但用户提到的是多项式枚举,所以可能递归在这里的应用需要结合剪枝或其他优化,使其复杂度保持在多项式级别。 用户可能混淆了多项式指数枚举,需要明确两者的区别。根据引用[2],多项式的状态空间规模是n^k,用循环或递推;而指数是k^n,用递归。但用户的问题明确是多项式,所以递推更常见,但递归在某些情况下也能应用,如组合数问题,结合剪枝控制复杂度。 需要检查之前的回答是否正确,比如之前的回答提到递推用于组合数(多项式时间),递归用于全排列(指数时间)。但用户现在的问题是关于多项式枚举,所以递归的应用可能需要调整,或者说明在特定情况下递归如何配合剪枝来维持多项式复杂度。 另外,引用[3]提到还原现场的重要性,这在递归处理枚举时很关键,比如回溯时需要恢复状态。应用实例部分可以举组合数生成的递归方法,虽然组合数的总数是C(n,m),但递归实现时通过剪枝避免重复路径,保持多项式时间。 需要结构清晰,分定义、底层逻辑、应用三部分。定义部分引用[1],底层逻辑引用状态空间遍历和还原现场,应用部分结合递推的组合数计算和递归的组合生成(剪枝),以及分治中的坐标变换案例(引用[5])。 注意区分递推递归的不同应用场景,递推适合有序、可复用状态的问题,递归适合需要路径探索和分支的情况,但通过剪枝控制在多项式时间。同时,动态规划(引用[4])作为递推的高级形式,可以提及但可能超出当前问题的范围。 最后,确保回答符合格式要求:使用中文,数学公式用$...$,独立公式用$$...$$,代码块正确,相关问题生成。检查是否有遗漏的引用,并正确标注。</think>### 递推递归在多项式枚举中的核心知识点解析 --- #### **一、定义本质差异** **递推**和**递归**是遍历算法问题状态空间的两种基本方式[^1]: - **递推**:通过**已知初始状态**和**递推公式**逐步推导出后续状态。例如计算组合数$C(n,k)$时,利用递推公式: $$ C(n,k) = C(n-1,k-1) + C(n-1,k) $$ - **递归**:将问题分解为**结构相同的子问题**,通过函数自我调用实现。例如生成组合时,递归选择/不选当前元素,并缩小问题规模。 **多项式枚举**的特征是状态空间规模为$O(n^k)$(如$n^2$, $n^3$),而递推递归在此场景下的选择取决于**状态复用性**和**路径复杂度**[^2]。 --- #### **二、底层逻辑对比** | **维度** | **递推** | **递归** | |----------------|-------------------------------------------|-------------------------------------------| | **实现方式** | 循环迭代,显式维护状态数组(如动态规划) | 函数调用栈隐式管理状态,天然支持回溯 | | **空间效率** | 通常$O(n^k)$,可通过滚动数组优化到$O(n)$ | 栈深度$O(k)$(递归树高度) | | **核心优势** | 无函数调用开销,适合密集计算 | 直观描述问题分治逻辑,适合路径探索 | | **关键限制** | 需明确状态转移方程 | 需处理递归终止条件和还原现场[^3] | --- #### **三、典应用场景** **1. 递推的简单应用** **案例**:计算杨辉三角(组合数) ```python def combination(n, k): dp = [1] * (k+1) # 滚动数组优化空间 for i in range(1, n+1): for j in range(min(i, k), 0, -1): dp[j] += dp[j-1] # 递推公式 return dp[k] ``` - **逻辑**:通过逆向更新避免状态覆盖,空间复杂度$O(k)$ - **数学基础**:组合数的递推公式$C(n,k)=C(n-1,k-1)+C(n-1,k)$ **2. 递归的简单应用** **案例**:生成所有长度为$k$的数字组合(允许重复) ```python def generate_combinations(n, k): res = [] def backtrack(path, start): if len(path) == k: res.append(path.copy()) return for i in range(start, n+1): path.append(i) backtrack(path, i) # 允许重复则传递i,否则i+1 path.pop() backtrack([], 1) return res ``` - **逻辑**:通过`start`参数控制选择范围,避免重复路径(剪枝) - **时间复杂度**:$O(n^k)$,但实际通过剪枝减少无效计算 --- #### **四、选择策略优化** 1. **递推优先场景** - 需要复用中间结果(如动态规划) - 问题具有单调性(如斐波那契数列) - 例如:网格路径计数问题,使用递推公式$dp[i][j] = dp[i-1][j] + dp[i][j-1]$ 2. **递归适用场景** - 需要探索多分支路径(如子集枚举) - 问题天然具有树形结构(如分形图形生成[^5]) - 例如:分形城市坐标计算,通过递归将$N$级城市分解为4个$N-1$级子城市 3. **混合优化技巧** - **记忆化递归**:将递归转化为带缓存的递推(如斐波那契数列优化) - **剪枝策略**:在递归中提前终止无效分支(如组合生成时限制选择范围) --- #### **五、关键问题总结** 1. **递推的本质是数学归纳法**,通过已知推导未知,适合**结构化状态转移**问题。 2. **递归的核心是分治思想**,通过自我调用缩小问题规模,需注意**递归深度**和**现场还原**。 3. **多项式枚举的关键**是控制状态空间增长在$O(n^k)$内,递推通过公式推导实现递归通过剪枝实现。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值