回溯法、全排列、子集等

回溯法

感想:回溯算法本质是一个循环,有点像while循环

一些回溯法(递归)的经典应用

1.全排列
2.子集

其实上面两个点,也是对应着高中数学里面的“排列”与“组合”

1.全排列问题

给定一个集合S{a,b,c},把其中元素按照不同顺序进行排序,eg.“abc”,“bca”,“cab”…全排列的结果为n!个。

基本思想是树(解答树)的遍历,如果是使用dfs(暴搜),那么可以使用递归来写。

在这里插入图片描述

解答树
/*
暴力全排列的思路是:
维护一个path容器,用来装选择好的内容,从集合S中获取元素[i],然后查询path中是否存在[i],如果不存在,跳过该元素,遍历下一个,如果[i]在path中不存在,则将[i]放入path中。
不断重复这个过程,使用dfs进行纵向遍历,使用for循环进行横向遍历。
*/
//伪代码
void dfs(int k){//k层数
    if(k = n) save(path);//保存path,也就是保存一个答案
    else{//用else省一个return语句
        
        for(int i = 0; i < n; i++){
            if(!check(S[i])){//检查S[i]是否在path中存在
                state.set(S[i]) = true;//
                path.add(S[i]);
                dfs(k+1);//向下遍历
                state.set(S[i]) = false;//去掉该元素,为下一个元素放置做好准备(元素+状态的还原)
                path.remove(S[i]);
            }
        }
        
    }
}
//样例代码见package cjm.recursion.full_permutation;
2.子集

子集问题描述:使用集合S{1,2,3}中的元素构建新的集合,每个元素只能使用一次,元素一样的集合只算一个,eg.{1,2},{2},{1,2,3}…

其实这个子集问题的本质就是高中学到的组合问题,n个元素有几种组合方式,答案数量为C(n,m);

增量构造法
/*
思路:与全排列的算法框架类似,也是对解答树进行遍历,不过不同点在于每一次遍历时都要将path加入答案集ans{},而且将S[i]放到前缀后时所需的判断也是不一样的。具体来说,[i]如果不在path中,且前缀+[i]构成的新集合如果不在答案集中,那么可以将[i]放入path中,并进行遍历。
本质还是dfs纵向遍历+for的横向遍历。
*/
void dfs(int k){//y总那边用的是u
    for(int i = 0; i < n; i++){
        if(!check(S[i])){//检查S[i]是否满足条件([i]属于path,path+[i]属于ans)
            setState(S[i]);//更新状态,包括将元素加入path,更新新集合在ans的存在等等
            dfs(k+1);//向下遍历
            reState(S[i]);//恢复状态
        }
    }}
位向量法

先空着,有空再学再写

二进制法

先空着,有空再学再写

引用:紫书

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
回溯法是一种常用于解决组合问题的算法,可以用来解决子集全排列问题。 对于子集和问题,可以使用回溯法来求解。具体步骤如下: 1. 定义一个数组来存储当前的子集,初始为空集。 2. 从原始数组的第一个元素开始,依次将元素加入到当前的子集中,并计算子集的和。 3. 如果子集的和等于目标和,则将当前的子集加入到结果集中。 4. 如果子集的和小于目标和,则继续向下搜索,将下一个元素加入到子集中。 5. 如果子集的和大于目标和,则回溯到上一个元素,将其从子集中删除,并继续向下搜索。 6. 如果已经搜索到原始数组的最后一个元素,且子集的和不等于目标和,则回溯到上一个元素,将其从子集中删除,并继续向下搜索。 7. 重复步骤2到步骤6,直到搜索完所有的子集。 对于全排列问题,也可以使用回溯法来求解。具体步骤如下: 1. 定义一个数组来存储当前的排列,初始为空。 2. 从原始数组的第一个元素开始,依次将元素加入到当前的排列中。 3. 如果当前的排列长度等于原始数组的长度,则将当前的排列加入到结果集中。 4. 如果当前的排列长度小于原始数组的长度,则继续向下搜索,将下一个元素加入到排列中。 5. 如果当前的排列中已经包含了某个元素,则回溯到上一个元素,将其从排列中删除,并继续向下搜索。 6. 如果已经搜索到原始数组的最后一个元素,且当前排列长度不等于原始数组的长度,则回溯到上一个元素,将其从排列中删除,并继续向下搜索。 7. 重复步骤2到步骤6,直到搜索完所有的排列。 需要注意的是,在回溯过程中,需要维护一个访问数组,用来记录哪些元素已经被访问过,避免重复访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值