蓝桥杯小白备战之递归枚举算法(上)-----快来跟我一起刷题up

哈喽,大家好!今天想跟大家分享三个最近刚刷的递归算法类型的题目,虽然题目类型标榜为简单,但是我感觉做出来尊的不简单啊。呜呜呜~~终究还是我太菜了。那就通过整理题目慢慢进步吧!一起刷题一起进步!!

目录

 一、递归实现指数型枚举

二、递归实现排列型枚举

三、递归实现组合型枚举

总结


 一、递归实现指数型枚举

问题描述

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

输入格式

输入一个整数n。

输出格式

每行输出一种方案。

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

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

数据范围

1\leq n\leq 15

输入样例

3

输出样例


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

问题的分析

对于本题,可以把输入的整数n想象成有n个坑,需要数字对应填入,每个坑可以填入数字也可以选择不填数字。以n=3为例,该问题的递归搜索树如下图

代码实现

n = int(input())#n表示最多有n个位置需要填数
# state列表存放当前每个位置是否填数,0表示正在考虑,1表示该位置填数,2表示该位置不填数
state = [0 for i in range(n)]
# 定义递归函数,u表示正在枚举索引为几的位置是否填数
def dfs(u):
    if u == n:#递归边界
        for i in range(n):#每个位置按字典序排序输出
            if state[i] == 1: #如果该位置放了数,就将其输出
                print("%d"%(i+1),end=" ")
        print()#每种可能换行表示
        return #return必须有,表示递归结束。如果没有会产生列表索引越界报错
    # 因为每个结点有两种情况,考虑每个结点的两个分支
    # 考虑第一种情况为该位置不放数
    state[u] = 2
    dfs(u+1)#递归搜索子树
    # 恢复现场
    state[u] = 0#该语句可以不加
    # 考虑第二种情况为该位置放数
    state[u] = 1
    dfs(u+1)#递归搜索子树
# 调用递归函数,从第一个位置开始递归枚举
dfs(0)

 

二、递归实现排列型枚举

问题描述

把1~n这n个整数排成一行后随机打乱顺序,输出所有可能的次序。

输入格式

一个整数n。

输出格式

按照从小到大的顺序输出所有方案,每行一个。

首先,同一行相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标一一比较,字典序较小的排在前面。

数据范围

1\leq n\leq 9

输入样例

3

输出样例

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

问题分析

以输入数据3为例,对1~3三个数字进行全排列,并且按照字典序较小的排在前面。将为题转化为有三个坑,每个坑上必须填入数字,遍历每一个坑,每个坑上都填入之前没有出现过的数字。对此绘制递归搜索树如下图

  代码实现

n = int(input())#表示对n个数进行全排列,有n个坑需要填数

# 因为每个坑不能填用过的数,所以需要有一个uesd列表,记录该数是否被用过
used = [0 for i in range(n)]#初始化时设为0,0表示该数没有被用过,1表示该数被用过

# ways列表记录每个位置填入了哪个数,初始化设为0,0表示该位置还未填数
ways = [0 for k in range(n)]

# 递归函数,u表示从索引为u的坑位上搜索
def dfs(u):
    if u == n:#递归边界,当u==n时表示所有的坑位已经填满,可以将坑位上的数字输出
        for i in range(n):#遍历每个坑位,并将其输出
            print("%d"%ways[i],end=" ")
        print()#每种遍历方式换行输出
        return
    # 遍历每一个分支
    for i in range(n):
        if used[i] == 0:#当该数没有输出时
            ways[u] = i + 1 #
            used[i] = 1#u索引位上填入了该数,则记录该数已经填过
            dfs(u+1)#搜索当前结点的下一个分支
            # 恢复现场
            used[i] = 0
            ways[u] = 0

# 表示一开始从索引为0的坑位上搜索
dfs(0)

运行结果

 

三、递归实现组合型枚举

问题描述

从1~n这n个整数中随机选出m个,输出所有可能的选择方案。

输入格式

两个整数n,m在同一行用空格隔开。

输出格式

按照从小到大的顺序输出所有的方案,每行1个。

首先,同一行的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7排在1 3 6 8前面)。

数据范围

n>0,

0\leq m\leq n,

n+(n-m)\leq 25

输入样例:

5 3

输出样例:

1 2 3 
1 2 4 
1 2 5 
1 3 4 
1 3 5 
1 4 5 
2 3 4 
2 3 5 
2 4 5 
3 4 5 

 

问题分析

输入的n为一共有1~n个数,输入的m为表示有m个坑需要填数。其中需要保证m个坑中前一个坑填的数比后一个坑填的数小。绘制递归搜索树如下图:

代码实现

n,m = input().split()
n = int(n)#表示有1~n个整数
m = int(m)#表示有m个坑等待填数
# 填过的数不能再填,uesd列表记录该数是否被填过,0表示未被填过,1表示该数被填过
used = [0 for i in range(n)]
# ways列表记录每个坑填入的数,初始化为0,表示还没填数
ways = [0 for k in range(m)]
stop = n//(m-1)+1
# 递归函数,u表示从索引为u的坑,next表示从第几个数开始搜索
def dfs(u,next):
    if u == m:#递归边界,表示枚举到最后一个坑的下一个坑时结束枚举,输出每个坑里的数
        for i in range(m):
            print("%d"%(ways[i]),end=" ")
        print()
        return
    # 遍历每一个分支,并且每一个分支从上一个选择的数后面开始枚举

    for i in range(next,n):
        if used[i] == 0:
            ways[u] = i+1
            used[i] = 1
            dfs(u+1,i+1)

            # 恢复现场
            used[i] = 0
            ways[u] = 0


# 表示第一个坑,从第一个数开始搜索
dfs(0,0)

运行结果

 

总结

关于递归枚举问题,需要通过输入和输出的样例进行问题的分析,画出递归搜索树。根据搜索树进行代码的书写。递归出口就是递归边界,一定要由return语句,表示递归结束,不然会报错。掌握套路,每一次递归下一层时需要恢复现场,上述三题都是根据每个坑进行枚举的,所以有一个state或者是ways列表记录枚举到第几个坑以及每个坑上的数据。对于不能重复填入的数字,可以用used数组进行记录该位置是否被使用过。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值