分支界限法
介绍
分支界限法(Branch and Bound)是一种在搜索问题中用于优化解空间搜索的算法。它可以在搜索过程中动态地生成子问题,通过一定的策略选择最具有潜力的子问题进行求解,并且可以快速排除那些不能优化目标的子问题,从而缩小搜索空间,提高求解效率。
通俗来讲,分支界限法就是在搜索问题时,通过先生成一个大问题,再把它分成许多小问题,然后一步一步地解决这些小问题,找到最优解。在这个过程中,我们还会根据当前的解空间来确定哪些问题没有必要再去尝试,从而加快搜索的速度。
总之,分支界限法是一种高效的搜索算法,可以在很多优化问题中发挥重要的作用。
示例求解
考虑如下 0 - 1背包问题
n = 4, w = [3, 5, 2, 1], v = [9, 10, 7, 4], c = 7
求解问题一定要明确自己再干什么,分支界限法实际上是一种剪枝的过程,而不是造树的过程,树已经造好了,做到心中有树,我们要把满二叉树尽可能的剪枝,然后求得最优解
如何剪枝?
- 如果生成不了最优解,那么舍弃,考虑把当前位置以及之后的全部物品全选,看看能不能超过当前最优解
- 如果放不下,那么舍弃
- 选择过程中直接更新最大值,而不是在每一层的选择完毕才更新,这样做能加速1的步骤
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import java.util.*;
public class BranchBound { static class State { int i, cv, rc;
public State(int i, int cv, int rc) { this.i = i; this.cv = cv; this.rc = rc; } }
public int knapsack(int n, int[] w, int[] v, int c) { int res = 0; int[] s = new int[n + 1]; for (int i = 1; i <= n; i++) s[i] = s[i - 1] + v[i - 1]; Queue<State> q = new LinkedList<>(); q.offer(new State(0, 0, c)); while (!q.isEmpty()) { State now = q.poll(); int i = now.i, cv = now.cv, rc = now.rc; if (i >= n) break; int rp0 = s[n] - s[i + 1], rp1 = s[n] - s[i]; if (rc >= w[i] && rp1 + cv > res) { q.offer(new State(i + 1, cv + v[i], rc - w[i])); res = Math.max(res, cv + v[i]); } if (rp0 + cv > res) { q.offer(new State(i + 1, cv, rc)); res = Math.max(res, cv); } } return res; }
public static void main(String[] args) { BranchBound solve = new BranchBound(); int[] w = {3, 5, 2, 1}; int[] v = {9, 10, 7, 4}; System.out.println(solve.knapsack(4, w, v, 7)); } }
|