回溯法

算法设计方法概览

僤鯓⒐⒋嵵緔 提交于 2020-01-19 00:49:21
算法设计方法概览 文章目录 算法设计方法概览 递归算法 什么是递归 定义及分类 直接递归 间接递归 尾递归 使用场景 递归模型 递归算法设计 递归与数学归纳法 第一数学归纳法 第二数学归纳法 递归算法设计的一般步骤 分治算法 分治法概述 使用场景 分治法的求解过程 蛮力法 蛮力法概述 使用场景 回溯法 问题的解空间 概述 种类 什么是回溯法 使用回溯法的一般步骤 分枝限界法 什么是分枝限界法 分枝限界法的设计思想 1. 设计合适的限界函数 2. 组织活结点表 3. 确定最优解的解向量 采用分枝限界法的三个关键问题 贪心法 贪心法概述 贪心法应用约束 贪心选择性质 最优子结构性质 动态规划 动态规划的原理 动态规划求解的基本步骤 动态规划与其他方法的比较 递归算法 什么是递归 定义及分类 直接递归 在定义一个过程或者函数时,出现调用本过程或本函数的成分,称之为递归。如果调用自身,称之为直接递归; 间接递归 若过程或者函数p调用过程或者函数q,而q又调用p,称之为间接递归; 任何间接递归都可以等价地转换为直接递归; 尾递归 如果一个递归过程或递归函数中递归调用语句是最后一条执行语句,则称这种递归为尾递归; 使用场景 可以使用递归解决的问题,应该满足以下三个特点: 需要解决的问题可以转换为一个或多个子问题来求解,而这些子问题的求解方法和原问题完全相同,只是数据规模不同;

回溯法

最后都变了- 提交于 2020-01-18 02:49:35
1. 定义    回溯法 是一种优选搜索法,又称为试探法,按优选条件向前搜索,以达到目标。但当搜索到某一步时,发现原先选择并不忧或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 回溯点 。 2. 解题步骤 (1)针对所给问题,确定问题的解空间: 首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。 (2)确定结点的扩展搜索规则 (3)以 深度优先方式 搜索解空间,并在搜索过程中用 剪枝函数 避免无效搜索。 3. 算法框架 递归算法框架 Input : X = { X1 , X2 , . . . , Xn } Output : T = ( t1 , t2 , . . . , tn ) back - track - rec ( int now ) { for x0 in X { T [ now ] = x0 if ( T [ 0. . . now ] is valid ) //如果有效则进行,否则尝试下一个x0 { if ( now == n ) //是完整解 { print ( T [ 1. . . now ] ) ; return ; } else if ( now < n ) //是部分解 { back - track - rec ( now + 1 ) ; } } } } 非递归算法 Input : X

算法设计与分析

☆樱花仙子☆ 提交于 2020-01-15 01:35:56
一、算法思想 (一)分治法(divide and conquer method) 是将待求解的原问题划分成k个较小规模的子问题,对这k个子问题分别求解。如果子问题的规模仍然不够小,则再将每个子问题划分为k个规模更小的子问题,如此分解下去,直到问题规模足够小,很容易求出其解为止(子问题求解思路一致),再将子问题的解合并为一个更大规模的问题的解,自底向上逐步求出原问题的解。 (二)动态规划法(dynamic programing method) 是将待求解问题分解成若干个相互重叠的子问题,每个子问题对应决策过程的一个阶段,一般来说,子问题的重叠关系表现在对给定问题求解的递推关系(也就是动态规划函数)中,将子问题的解求解一次并填入表中,当需要再次求解此子问题时,可以通过查表获得该子问题的解而不用再次求解,从而避免了大量重复计算。 (三)贪心法(greedy method) 贪心法在解决问题的策略上目光短浅,只根据当前已有的信息就做出选择,而且一旦做出了选择,不管将来有什么结果,这个选择都不会改变。换言之,贪心法并不是从整体最优考虑,它所做出的选择只是在某种意义上的局部最优。这种局部最优选择并不总能获得整体最优解(Optimal Solution),但通常能获得近似最优解(Near-Optimal Solution)。 (四)回溯法(back track method)

回溯法——20200106

烈酒焚心 提交于 2020-01-10 04:53:12
6 Leetcode1239.串联字符串的最大长度 6.1 题目描述 给定一个字符串数组 arr,字符串 s 是将 arr 某一子序列字符串连接所得的字符串,如果 s 中的每一个字符都只出现过一次,那么它就是一个可行解。 请返回所有可行解 s 中最长长度。 示例 1: 输入:arr = [“un”,“iq”,“ue”] 输出:4 解释:所有可能的串联组合是 “”,“un”,“iq”,“ue”,“uniq” 和 “ique”,最大长度为 4。 示例 2: 输入:arr = [“cha”,“r”,“act”,“ers”] 输出:6 解释:可能的解答有 “chaers” 和 “acters”。 示例 3: 输入:arr = [“abcdefghijklmnopqrstuvwxyz”] 输出:26 提示: 1 <= arr.length <= 16 1 <= arr[i].length <= 26 arr[i] 中只含有小写英文字母 6.2 分析 回溯法,分为使用当前的和不使用当前的两种。 6.3 代码 #define MAX_LEN 420 bool isRepeat(char* str) { if(str == NULL || strlen(str) == 0) { return false; } int strLen = strlen(str); int i = 0; int cnt

5.3 回溯法解决最佳调度问题

流过昼夜 提交于 2019-12-27 14:32:43
1.实验目的 回溯法解决最佳调度问题 2.实验内容 2.1 问题描述 设有n个任务由k个可并行工作的机器来完成,完成任务i需要时间为ti。试设计一个算法找出完成这n个任务的最佳调度,使完成全部任务的时间最早。 2.2 问题分析 该算法可抽象为子集树回溯算法,针对特定的任务数和机器数定义解空间,对于n个任务和k个机器, 解编码:(X1,X2,。。。,Xn),Xi表示给任务i分配的机器编号;解空间:{(X1,X2,。。。,Xn)| Xi属于S,i=1到n},S={1,2,。。。,k}。以下图为例: 解空间如图。在这个图中能清晰地说明问题。 3叉树表示机器数为3。深度为4,总共4层,表示任务数为4。 用3台机器去调度4个任务,把这棵树深度遍历,最后选出最优值。 3.实验过程及结果 3.1 数据输入 Machine = 4 time = [ ] for i in range ( 100 ) : time.append ( random.randint ( 1,50 )) time.sort ( ) time.reverse ( ) total = [ 0,0,0,0 ] 假设有4台机器,随机生成100个任务,任务的时间范围在0~50 3.2 实验代码 def main ( time ) : for i in time: min_time = total [ 0 ] k = 0 for j

符号三角形问题-回溯法

前提是你 提交于 2019-12-27 01:21:01
问题描述:   由14个“+”号和14个“-”号组成的符号三角形。   2个同号下面是“+”号,2个异号下面是“-”号。 如图:    +   +   _   +   _   +   +    +  _   _   _   _   +      _   +  +  +  _        _   +   +  _          _   +  _           _  _            + 在一般情况下,符号三角形第一行有N个符号,该问题要求对于给定n计算有多少种不同的符号三角形。使其所含的+ — 个数相同。 算法设计:    1 x[i] =1 时,符号三角形的第一行的第i个符号为+   2 x[i] =0时,表示符号三角形的第一行的第i个符号位-       共有i(i+1)/2个符号组成的符号三角形。   3 确定x[i+1]的值后,只要在前面确定的符号三角形的右边加一条边就扩展为x[1:i+1]所相应的符号三角形。   4 最后三角形中包含的“+”“-”的个数都为i(i+1)/4,因此搜索时,个数不能超过...若超直接可以剪去分枝。   5 当给定的n(n+1)/2为奇数时,也不符合三角形要求。 算法描述: class Triangle { friend int Compute(int); private: void Backtrack(int t); int

张三木教你理解回溯法

旧街凉风 提交于 2019-12-19 21:50:08
回溯法 回溯法(搜索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当搜索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择。这种走不通就退回再走的技术为回溯法。而满足回溯条件的某个状态的点称为“回溯点”。 回溯法问题的框架 问题的解空间 复杂问题常常有很多的可能解,这些可能的解构成了问题的解空间。 解空间就是进行穷举的搜索空间 ,所以解空间中应该包含所有的可能解,且至少应该包含问题的一个最优解。例如:对于有n个物品的0/1背包问题,当n=3时,其解空间是:{(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1) }。 回溯法的基本思想 基本步骤 针对所给的问题,定义问题的解空间 确定易于搜索的解空间结构 以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索 常用剪枝函数 约束函数:减去不满足条件的子树 限界函数:减去得不到最优解的子树 递归和迭代回溯 递归回溯 模板: void Backtrack( int t ){ if ( f > n ) { Output(x); }else{ for( int i = f(n,t), i<=g(n,t);i++){ x[t] = h(i); if(Constraint(t)

回溯法解决八皇后问题

巧了我就是萌 提交于 2019-12-18 18:41:58
1.“八皇后”问题 八皇后问题是十九世纪著名数学家高斯于1850年提出的。问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意的两个皇后不能处在同一行,同一列,或同一斜线上。可以把八皇后问题拓展为n皇后问题,即在n*n的棋盘上摆放n个皇后,使其任意两个皇后都不能处于同一行、同一列或同一斜线上。 2.冲突条件判断 如下图,方块内的值(i,j)表示第i行第j列。(1,1)位置如果放了皇后,那么(1,1)位置所在的行,列,斜线上都不能再放皇后。 如何判断两个位置冲突呢? (1)判断两个位置是否再斜线上:根据斜率 A(1,1)位置,B(2,0)位置和C(2,2)位置,A和B冲突:(0-1)/(2-1)==-1,A和C冲突:(2-1)/(2-1)==1。 因此,对于任意两点A(x1,y1)和B(x2,y2),两点斜线冲突满足条件:abs((y2-y1)/(x2-x1))==1, 该公式转换为: abs(y2-y1)== abs(x2-x1) (2)判断两个位置是否在同一列/同一行 任意两点A(x1,y1)和B(x2,y2)在同一列满足条件: y1 == y2 ,在同一行满足条件: x1 == x2 判断冲突代码如下: int valid(int row, int col) //判断第row行第col列是否可以放置皇后 { int i; for (i = 0; i < QUEEN;

回溯法解决0-1背包问题

て烟熏妆下的殇ゞ 提交于 2019-12-17 00:18:47
问题描述:    有 n 件物品和一个容量为 c 的背包。第 i件物品的价值是 v [i],重量是 w[i]。求解将哪些物品装入背包可使价值总和最大。 所谓01背包,表示每一个物品只有一个,要么装入,要么不装入。 回溯法 :   01背包属于找最优解问题,用回溯法需要构造解的子集树。在搜索状态空间树时,只要左子节点是可一个可行结点,搜索就进入其左子树。对于右子树时,先计算上界函数,以判断是否将其减去,剪枝啦啦! 上界函数bound():当前价值cw+剩余容量可容纳的最大价值<=当前最优价值bestp。 为了更好地计算和运用上界函数剪枝,选择先将物品按照其单位重量价值从大到小排序,此后就按照顺序考虑各个物品。 #include <stdio.h> #include <conio.h> int n;//物品数量 double c;//背包容量 double v[100];//各个物品的价值 double w[100];//各个物品的重量 double cw = 0.0;//当前背包重量 double cp = 0.0;//当前背包中物品价值 double bestp = 0.0;//当前最优价值 double perp[100];//单位物品价值排序后 int order[100];//物品编号 int put[100];//设置是否装入 //按单位价值排序 void knapsack

素数环问题_JAVA实现_回溯法

别来无恙 提交于 2019-12-16 22:09:44
具体说明请看代码中的注释。 个人实现,如有Bug请指正。 /** * @Author = The Great Ke * @description: 素数环问题———— 采用回溯法 * @Date: Creat in 20:01 2019/12/16 * @modified by : */ public class SuShuHuan_Pro { //判断某整数是不是质数 public static boolean isp(int n){ for(int i = 2; i < Math.sqrt(n)+1;i++){ if(n % i == 0){ return false; } } return true; } public static int n = 6; public static boolean[] is_Used = new boolean[n+1];//存储某数是否被使用 public static int[] array = new int[n+1];//存放数列 public static void dfs(int cur){ if(cur == n+1 && isp(array[1]+ array[n]) && array[1] == 1){//如果最后一个数放进去了,并且最后一个数和第一个的和为质数,并且第一个数是1(因为我们只输出开头是1的,避免重复) for