说到回溯算法的本质是什么,其实是枚举。 在给定的枚举集合中,不断从中尝试搜索并找到问题的解,在搜索中发现不符合求解条件时,“回溯”返回,尝试其他路径进行搜索解决。 回溯法就是在这样不成功地返回后尝试其他路径的方法,许多复杂而大规模的问题都可以使用回溯法,因此回溯法有“通用求解法”的美称。
解决问题解决一个追溯问题实际上是决策树的遍历过程。 你只需要考虑三个问题:
1、路径:也就是已经选择了。
2、选择列表:也就是说,你现在可以做出的选择。
3、终止条件:即到达决策树底部,不能再选择的条件。
如果你不理解这三个词的解释,没关系。 我们稍后将使用“全序列”和“n-quean问题”这两个经典的回溯算法问题来理解这些词是什么意思。 现在,你首先给我留下了印象。
在代码方面,回溯算法框架:
result=[]def backtrack (路径,选择列表) : if退出条件: result.add (路径) return for选择in选择列表:选择backtrack (路径,选择列表)
选择和取消选择是什么呢? 这个框架的基础原理是什么呢? 在这里,我们通过“全排列”这个问题,解开迄今为止的疑问,详细探索其中的奥妙吧。
全排列问题我们高中的时候做过排列组合的数学题。 我们也知道n个不重复的数。 所有序列共享n! 个。
PS :为了便于理解,这次讨论的所有排列问题都不包含重复的数字。
那么,我们是怎么做到包罗万象地排队的呢? 例如,如果你举出三个数[ 1,2,3 ],你一定不会不规则粗暴地行动。 一般是这样的。
首先把第一位固定为1,然后把第二位定为2的话,第三位就只有3了。 然后第二名可以是3,第三名只能是2; 然后换了第一名成为第二名,只能紧追下一个第二名……
应用上述回溯算法的解题模板,进行深度优先的遍历,直到找到问题的解
公共类解决方案{
//*
*结果集
*/
privatestaticlistresult=new ArrayList (10;
/**参与所有数组的数字*/privatestaticlistintegernums=arrays.as list (1,2,3 ); /**当前阶段的解* @param selectedNums选定的解集合* @param selectableNums选项的解集合*/publicstaticvoidpermutation (listintegerselectednums list integer selectable nums {//)满足条件且结果集if (==selected nums.size ) //遍历各级的选项解集合for (inti=0; i selectableNums.size (; I ) integer num=selectable nums.get (I; //消除不符合条件的解,减少分枝的if(selectednums.contains(num ) ) { continue; //选择现阶段的解selectednums.add(num )之一; //选择完成后,进入下一个阶段permutation(selectednums,selectableNums ); //继续改变解遍历selectednums.remove(num ); } publicstaticvoidmain (string [ ] args ) listintegerselectednums=new ArrayList; permutation(selectedNUMS,nums ); system.out.println (arrays.tostring (result.to array () ); }