回溯法

递归与回溯思想的应用——以八皇后问题为例

独自空忆成欢 提交于 2020-01-31 14:54:42
1.递归与回溯 1.1递归 乍一听很高深,其实理解起来很轻松,但是面对问题时如何动手编写递归程序却十分棘手! 递归程序的流程图很清晰,非常直观。所谓递归,简单点来说,就是一个函数直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。 递归与循环有本质区别:简单来说,循环是有去无回,而递归则是有去有回(因为存在终止条件)。 递归与栈的关系:常常听到 “递归的过程就是出入栈的过程”,这句话怎么理解?我们以阶乘代码为例,取 n=3,则过程如下: 第 1~4 步,都是入栈过程,Factorial(3)调用了Factorial(2),Factorial(2)又接着调用Factorial(1),直到Factorial(0); 第 5 步,因 0 是递归结束条件,故不再入栈,此时栈高度为 4,即为我们平时所说的递归深度; 第 6~9 步,Factorial(0)做完,出栈,而Factorial(0)做完意味着Factorial(1)也做完,同样进行出栈,重复下去,直到所有的都出栈完毕,递归结束。 每一个递归程序都可以把它改写为非递归版本。我们只需利用栈,通过入栈和出栈两个操作就可以模拟递归的过程,二叉树的遍历无疑是这方面的代表。但是并不是每个递归程序都是那么容易被改写为非递归的。某些递归程序比较复杂,其入栈和出栈非常繁琐,给编码带来了很大难度

Leetcode刷题java之46. 全排列

一笑奈何 提交于 2020-01-30 16:38:46
回溯法框架参考这篇文章: https://blog.csdn.net/qq_41901915/article/details/104113330 执行结果: 通过 显示详情 执行用时 :2 ms, 在所有 Java 提交中击败了53.81% 的用户 内存消耗 :37.4 MB, 在所有 Java 提交中击败了52.98%的用户 题目: 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/permutations 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 思路: 采用回溯法,并利用回溯法框架 主要就是找到几个关键点 第一个 选择空间,当然也就是传入的数组 第二个就是路径,自己创建一个路径就可以了 结束的条件 代码: class Solution { List<List<Integer>> result=new LinkedList<>(); public List<List<Integer>> permute(int[] nums) { LinkedList<Integer> track=new

算法:回溯法 矩阵中的路径

不羁岁月 提交于 2020-01-30 10:03:44
题目:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径,路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子 利用回溯法:直接上代码 public static boolean hasPath(char[][] matrix,char[] str){ int rows= matrix.length; int cols = matrix[0].length; boolean[][] visited = new boolean[rows][cols]; int pathLength = 0; for(int row = 0 ; row < rows ; row++){ for(int col = 0 ; col < cols ; col++){ if(hasPathCore(matrix,rows,cols,row,col,str,pathLength,visited)){ return true; } } } return false; } private static boolean hasPathCore(char[][] matrix, int rows, int cols, int row, int col, char[] str, int pathLength,

最佳调度(回溯法)

走远了吗. 提交于 2020-01-30 04:39:07
最佳调度问题 【问题描述】 假设有n个任务由k个可并行工作的机器完成。完成任务i需要的时间为ti。试设计一个算法找出完成这n个任务的最佳调度,使得完成全部任务的时间最早。 【编程任务】 对任意给定的整数n和k,以及完成任务i需要的时间为ti,i=1~n。编程计算完成这n个任务的最佳调度。 【输入样例】 7 3 2 14 4 16 6 5 3 【输出样例】 17 首先列个七乘三的二维数组了解算法思路: 我们知道回溯法其实是穷举法加剪枝函数 我们的函数用到递归,层层返回。 解空间树为一颗n叉树,每搜索到叶子节点就更新一次最大值,是用一次搜索结束后三个机器中花费时间最长的机器的所用时间作为此次分配的所用时间。 上图:红色为第一次分配;黄背景色为第二次;加粗字体为第三次;下划线为第四次。从上到下递归,然后层层返回。 算法设计: 从n个作业中找出有最小完成时间和的作业调度,所以批处理作业调度问题的解空间是一棵排列树。按照回溯法搜索排列树的算法框架,设开始时t=[1,2, … , n]是所给的n个作业的完成时间,则相应的排列树由t[1:n]的所有排列构成。 数组len[]用于存储一组空间解,comp()函数用于计算一个完整调度的完成时间,search()函数用来做搜索,best记录相应的当前最佳作业调度完成时间。 当dep>n时,算法搜索至叶子结点,得到一个新的作业调度方案

回溯法、分支限界法解决旅行商TSP问题

瘦欲@ 提交于 2020-01-30 00:40:04
文章目录 TSP问题描述 回溯法解tsp问题(深度优先) 代码 基站数据 运行结果 分支限界法解tsp问题(广度优先) 代码 运行结果 结果分析 TSP问题描述 旅行商从驻地出发,经过每个需要访问的城市一次且只有一次,并最终返回出发点。如何安排路线,使旅行总路程最短?即求解最短哈密顿回路。 回溯法解tsp问题(深度优先) 以深度优先的方式,从根节点开始,依次扩展树节点,直到达到叶节点——搜索过程中动态产生解空间 代码 # include <stdio.h> # include <time.h> # include <stdlib.h> # define NUM 42 # define NoEdge 99999 struct MinHeapNode { //解空间树的节点 double lb , //子树费用的下界 cc ; //当前费用 int s , * x ; struct MinHeapNode * next ; } ; int bestx [ NUM + 1 ] ; //最优路径 int x [ NUM + 1 ] ; double cw = 0.0 , bestw = 99999.0 ; //cw是当前路径值,bestw是最优路径值 double * * w ; //距离矩阵 int count = 0 ; //计算节点数 MinHeapNode * head = 0 ;

算法第五章作业

最后都变了- 提交于 2020-01-28 00:28:05
1.对回溯算法的理解 回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。回溯法说白了就是穷举法。回溯法一般用递归来解决。回溯法一般都用在要给出多个可以实现最终条件的解的最终形式。回溯法要求对解要添加一些约束条件,包括选择,条件和结束。 回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。 2.请说明“子集和”问题的解空间结构和约束函数 解空间结构为二叉树,第i层到第i+1层表示是否选择第i个元素,向左表示选择,向右表示不选择。 约束函数:利用rest(当前元素加到最后一个元素的总和)+ sum(当前所选元素之和)>= c作为限界剪枝。 3.请说明在本章学习过程中遇到的问题及结对编程的情况 这一章的学习我们遇到了很多问题,比如对回溯结束条件的判断,以及各种剪枝的方法选择,很多点难以很快想到,导致程序经常存在各种各样的问题,很容易判定不足和程序超时,这让人很是苦恼。但是我们小组还是一起解决了很多问题,也更多地认识到了自己的不足。 来源: https:/

算法的设计技术

非 Y 不嫁゛ 提交于 2020-01-27 11:39:44
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ght886/article/details/80289142 分治法 概念: 将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。 思想策略: 对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。 特征: 1) 该问题的规模缩小到一定的程度就可以容易地解决 2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。 3) 利用该问题分解出的子问题的解可以合并为该问题的解; 4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。 第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加; 第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;、 第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。 第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题

※39. 组合总和(java)(回溯法)

五迷三道 提交于 2020-01-23 21:36:19
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 说明: 所有数字(包括 target)都是正整数。 解集不能包含重复的组合。 示例 1: 输入: candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ] 示例 2: 输入: candidates = [2,3,5], target = 8, 所求解集为: [ [2,2,2,2], [2,3,3], [3,5] ] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/combination-sum 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 回溯法 class Solution { LinkedList < List < Integer > > result = new LinkedList < > ( ) ; public List < List < Integer > > combinationSum ( int [ ] candidates , int target ) { LinkedList < Integer > list =

回溯法解决四皇后问题

旧城冷巷雨未停 提交于 2020-01-20 07:56:12
以4皇后为例,其他的N皇后问题以此类推。所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子。在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平、竖直、以及45度斜线上都不能出现皇后的棋子,例子 要求编程求出符合要求的情况的个数。四皇后问题有很多种解法,这里主要介绍一种经典的解决方法: 回溯法 回溯法的 基本思想 是:可以构建出一棵解空间树,通过探索这棵解空间树,可以得到四皇后问题的一种或几种解。这样的解空间树有四棵 在如上图所示的4×4的棋盘上,按列来摆放棋子,首先因为皇后棋子不能在同一列,所以先排除有2个或2个以上的棋子在同一列的情况,所以第一个棋子在第一列有4种摆放方法(第1列第1行,第1列第2行,第1列第3行,第1列第4行),同样第二个棋子在第二列有4种,同样第三个棋子在第三列有4种,同样第四个棋子在第四列有4种,所以进行简单的排除不在同一列的情况后,还有4×4×4×4=256种可能,但是在这256种可能里,依然存在比如棋子在同一行,或在45度斜线上的情况出现。另一个角度思考,所有的满足四皇后问题的摆放方式一定都存在于这256种情况之中。简单的理解就是:这256种棋盘局面包含了所有满足4皇后问题的解,但是不包含全部的棋盘局面。 下面是解空间树的示例(以上一段的按列摆放的方式来进行示例讲解),其中第i层的棋盘局面是在第i

python3 回溯法解决八皇后问题--详细解释

北城余情 提交于 2020-01-20 02:12:25
问题: 国际象棋棋盘是8 * 8的方格,每个方格里放一个棋子。皇后这种棋子可以攻击同一行或者同一列或者斜线(左上左下右上右下四个方向)上的棋子。在一个棋盘上如果要放八个皇后,使得她们互相之间不能攻击(即任意两两之间都不同行不同列不同斜线),求出一种(进一步的,所有)布局方式。 思路: (粘贴一波网上已有的递归思路,就不码字了)第一个需要解决的小问题就是,如何用数学的语言来表述斜线上重叠的皇后。其实我们可以看到,对于位于(i,j)位置的皇后而言,其四个方向斜线上的格子下标分别是 (i-n,j+n), (i-n,j-n), (i+n,j-n), (i+n,j+n)。当然i和j的±n都要在[0,7]的范围内,保持不越界。暂时抛开越界限制不管,这个关系其实就是: 目标格子(a,b)和本格子(i,j)在同一条斜线上 等价于 |a - i| == |b - j| 。 然后,从递归的思想来看,我们在从第一行开始给每一行的皇后确定一个位置。每来到新的一行时,对本行的所有可能位置(皇后放在这个位置和前面所有已放置的皇后无冲突)分别进行递归地深入;若某一行可能的位置数为0,则表明这是一条死路,返回上一层递归寻找其他办法;若来到的这一行是第九行(不存在第九行,只不过是说明前八行都已经正确配置,已经得到一个解决方案),这说明得到解决方案。 可以看到,寻找一行内皇后应该摆放的位置这是个递归过程