网站互联,关键词做网站标题是什么意思,wordpress 表格主题,wordpress调取列表页一#xff0c;回溯法思想 一般教科书概念上的讲解 回溯算法实际上一个类似枚举的搜索尝试过程#xff0c;主要是在搜索尝试过程中寻找问题的解#xff0c;当发现已不满足求解条件时#xff0c;就“回溯”返回#xff0c;尝试别的路径。 回溯法是一种选优搜索法#xff0c…一回溯法思想 一般教科书概念上的讲解 回溯算法实际上一个类似枚举的搜索尝试过程主要是在搜索尝试过程中寻找问题的解当发现已不满足求解条件时就“回溯”返回尝试别的路径。 回溯法是一种选优搜索法按选优条件向前搜索以达到目标。但当探索到某一步时发现原先选择并不优或达不到目标就退回一步重新选择这种走不通就退回再走的技术为回溯法而满足回溯条件的某个状态的点称为“回溯点”。 许多复杂的规模较大的问题都可以使用回溯法有“通用解题方法”的美称。
基本思想 在包含问题的所有解的解空间树中按照深度优先搜索的策略从根结点出发深度探索解空间树。当探索到某一结点时要先判断该结点是否包含问题的解如果包含就从该结点出发继续探索下去如果该结点不包含问题的解则逐层向其祖先结点回溯。其实回溯法就是对隐式图的深度优先搜索算法。 若用回溯法求问题的所有解时要回溯到根且根结点的所有可行的子树都要已被搜索遍才结束。 而若使用回溯法求任一个解时只要搜索到问题的一个解就可以结束。 解题一般步骤 1针对所给问题确定问题的解空间首先应明确定义问题的解空间问题的解空间应至少包含问题的一个最优解。 2确定结点的扩展搜索规则 3以深度优先方式搜索解空间并在搜索过程中用剪枝函数避免无效搜索。 二回溯法典型 1八皇后问题 问题描述八皇后问题是一个以国际象棋为背景的问题如何能够在 8×8 的国际象棋棋盘上放置八个皇后使得任何一个皇后都无法直接吃掉其他的皇后为了达到此目的任两个皇后都不能处于同一条横行、纵行或斜线上。 转化规则其实八皇后问题可以推广为更一般的n皇后摆放问题这时棋盘的大小变为n×n而皇后个数也变成n。当且仅当 n 1 或 n ≥ 4 时问题有解。令一个一维数组a[n]保存所得解其中a[i] 表示把第i个皇后放在第i行的列数注意i的值都是从0开始计算的下面就八皇后问题的约束条件。 1因为所有的皇后都不能放在同一列因此任意两个a[0].....a[7]的值不能存在相同的两个值。 2所有的皇后都不能在对角线上那么该如何检测两个皇后是否在同一个对角线上我们将棋盘的方格成一个二维数组如下 假设有两个皇后被放置在ij和kl的位置上明显当且仅当|i-k||j-l| 时两个皇后才在同一条对角线上。 穷举法
#include iostream
#include algorithm
#include iterator
#include vectorusing namespace std;//位置冲突算法
bool isMeet(int a[], int n)//a[]位置数组n皇后个数
{for (int i 2; i n; i)//i位置 for (int j 1; j i; j)//j位置 if ((a[i] a[j]) || (abs(a[i] - a[j]) i - j))//1在一行2在对角线上 return false; //冲突 return true;//不冲突
}
//八皇后枚举算法 //主函数
int main()
{int a[9] { 0 }; //用于记录皇后位置(第0行0列我们不用)。如a[3] 4;表示第3列第4行位置有皇后int count 0; //用于计数 for (a[1] 1; a[1] 8; a[1])for (a[2] 1; a[2] 8; a[2])for (a[3] 1; a[3] 8; a[3])for (a[4] 1; a[4] 8; a[4])for (a[5] 1; a[5] 8; a[5])for (a[6] 1; a[6] 8; a[6])for (a[7] 1; a[7] 8; a[7])for (a[8] 1; a[8] 8; a[8]){if (!isMeet(a, 8))//如果冲突则继续枚举 continue;elsecount;}cout count endl;system(pause);return 0;
} 回溯法递归版
见leecodeLeetCode OJ 52. N-Queens II
#include iostream
#include algorithm
#include iterator
#include vectorusing namespace std;int a[9] { 0 };
int n 8, cnt 0;//位置冲突算法
bool isConflict(int a[], int n)//a[]位置数组n皇后个数
{int i 0, j 0;for (i 2; i n; i)//i位置 for (j 1; j i - 1; j)//j位置 if ((a[i] a[j]) || (abs(a[i] - a[j]) i - j))//1在一行2在对角线上 return false; //冲突 return true;//不冲突
}//八皇后问题回溯算法递归版
void Queens8(int k) //参数k递归摆放第k个皇后
{int i 0;if (k n) //kn即k8表示最后一个皇后摆放完毕 {printf(第%d种情况, cnt);for (i 1; i n; i)printf(%d , a[i]);//打印情况 printf(\n);}else //8个皇后未全部摆放完毕 {for (i 1; i n; i)//摆放第k个皇后时转下一行 { //依次从列顶端开始搜索一直到列底端直到找到合适位置,如果未找到自动返回上层递归(回溯) a[k] i;if (isConflict(a, k))Queens8(k 1);//不冲突,递归摆放下一个皇后}}return;
}//主函数
int main()
{Queens8(1);//参数1表示摆放第1个皇后 system(pause);return 0;
} 三典型例题
在leetcode中那些要求列举所有情况或者说所有情况都要探讨一下的的例题一般都可以考虑回溯法。
当遇到一个可以用到回溯法的时候需要按照如下步骤进行 1. 确定问题的一个解空间树 这个解空间树至少包含一个你需要的那个解 否则这个树就完全没有意义了 2. 组织好这棵树 弄明白这棵树的每一个节点代表什么 每一个分支代表什么 3. 从这棵树的根节点不断的向下深搜 当遇到不合适的节点的时候直接跳过以这个节点为根的子树 4. 当搜索到了叶子节点的时候就回溯 5. 不断的重复这个3 4步骤 附加 根据具体的问题可以定义限界条件 最优值条件 根据这两个条件可以剪枝了 以下是在leetcode中收集的典型例子。 LeetCode OJ 39 / 40 / 216 Combination Sum(I / II / III) 39题翻译题目 给定一组候选集C和一个目标值T在C的所有组合中找出所有总和等于T的组合。
候选数组C中同一个数可以被选择多次不限次数。 分析 典型的回溯法应用。 对数组里面的每个数用递归的方式相加每次递归将和sum与target作比较若相等则加入结果vectorsumtarget则舍弃并返回false若sumtarget则继续进行递归。若sumtarget则回溯到上一层重新以数组中的下一个数开始递归。 第一种sumtarget的情况下在加入结果vector后回溯此时不应再累加要将当前一种结果最后加入的元素pop_back()并继续对后面的元素进行递归 第二种sumtarget的情况下则需要将当前结果的最后加入的元素pop_back()并继续对后面的元素进行递归。 第三种sumtarget的情况下直接以当前数继续递归。 注意元素可以重复所以下一次递归总是从当前递归元素开始。 40题翻译题目 给定一组候选集C和一个目标值T在C的所有组合中找出所有总和等于T的组合。
候选数组C中每个数字只能使用一次。 分析 典型的回溯法应用。 这道题跟上一道题基本一模一样唯一区别就是每个数只能用一次因此代码上只需要改一点点就行即下一层递归 不能再从当前数开始而要从下一个数开始了。 41题翻译题目 找到有k个数组成的所有可能组合加起来等于数n。 k个数取值1到9每个数只能使用一次。确保在集合中的数字按顺序排列。 LeetCode OJ 78 / 90 Subsets I / II LeetCode OJ 46. / 47. Permutations (I / II) LeetCode OJ 22. Generate Parentheses LeetCode OJ 17. Letter Combinations of a Phone Number 注本博文为EbowTang原创后续可能继续更新本文。如果转载请务必复制本条信息 原文地址http://blog.csdn.net/ebowtang/article/details/38145433 原作者博客http://blog.csdn.net/ebowtang 参考资源 【1】写的很不错很清楚http://www.2cto.com/kf/201405/302318.html