今天写一下回溯算法。
关于回溯算法,我认为回溯本质而言就是一个递归(一个深度遍历DFS),只不过这个递归过程看好是遇到不合适的就往回走,然后继续遍历。那么如何选取到最合适的解决方案呢,那就是在遍历的过程中加入一个“记事本”,这个记事本用来记录当前已经拿到的最好的结果,在后续的遍历过程中,如果有更好的结果,就把当前结果进行替换。
但是递归的复杂度太高了,有没有什么好的解决办法呢,就是加上剪枝过程,根据实际题目条件加上限制用来剪枝,让不必要的遍历直接跳过。
一个典型的背包问题0-1问题,就是可以用回溯来解决,回溯可以转化为递归树,其实就是一个二叉树,而回溯就是二叉树的DFS遍历,至此,回溯算法的本质已经讲清楚了。如果还有不理解,请看下面的例子,和一篇好文章:
文章(回溯和递归树、二叉树的关系):https://blog.csdn.net/yhflyl/article/details/86763197
例子:
问题:背包问题
解答:
public int maxW = Integer.MIN_VALUE; //存储背包中物品总重量的最大值
// cw表示当前已经装进去的物品的重量和;i表示考察到哪个物品了;
// w背包重量;items表示每个物品的重量;n表示物品个数
// 假设背包可承受重量100,物品个数10,物品重量存储在数组a中,那可以这样调用函数:
// f(0, 0, a, 10, 100)
public void f(int i, int cw, int[] items, int n, int w) {
if (cw == w || i == n) { // cw==w表示装满了;i==n表示已经考察完所有的物品
if (cw > maxW) maxW = cw;
return;
}
f(i+1, cw, items, n, w);
if (cw + items[i] <= w) {// 已经超过可以背包承受的重量的时候,就不要再装了,剪枝过程!
f(i+1,cw + items[i], items, n, w);
}
}
收工~