搜索算法、装载问题
搜索算法
解空间树
子集树
比如n种可选物品的01背包,对其进行选择。解空间为长度为n的01向量表示。解空间树是一颗完全二叉树。
排列树
比如旅行商问题,对n进行排列。
解空间搜索方式
DFS
深度优先。回溯法
。
BFS
广度优先或最小耗费优先。分支限界法
。
在扩展节点处,先生成所有的儿子节点,再从活节点列表中选择一个最有利的节点作为新的扩展节点。
回溯法
就是穷举,深度优先去找到解空间中满足约束条件的所有解,再选择一个最好的出来。
类似于走迷宫:走到死路或者已经达不到最优解就及时回头。要注意剪枝。
搜索子集树
1 | void dfs(int t) { |
搜索排列树
1 | void dfs(int t) { |
分支限界法
广度优先或者最小消费优先去搜索解空间树,去找到使目标函数达到极大或者极小解,某种意义下的最优解。
每个活节点只有一次机会成为扩展节点,成为时,就一次性产生其所有儿子节点。舍弃不可行或导致非最优解的儿子节点,其余儿子节点加入活节点列表。从活节点列表中取出下一个节点作为新的扩展节点。
广度优先搜索
队列式分支限界法
最小消费优先搜索
优先队列式分支限界法。每个活节点有一个优先级。通常用最大堆来实现最大优先队列。
装载问题
问题描述
\(n\)个集装箱质量分别为\(w_i\), 要装上总容量为\(c\)的轮船。 问,怎样装,才能使装得最多? \[ \begin{align} & \max \sum_{i}^nx_i\cdot w_i \\ & \sum_{i}^nx_i\cdot w_i \le c \\ & x_i \in\{0,1\}, \quad \text{表示装或不装} \end{align} \]
贪心解法
贪心策略:集装箱从轻到重排序,轻者先装, 直到超重。
BFS
有2艘轮船,\(\sum_i^n w_i \le c_1 + c_2\), 怎样才能把n个集装箱装到这2艘轮船。
可知最优方案:尽量把第一艘轮船装满,剩余的装到第二艘上。
定义Solution
1 | class Solution { |
无剪枝的dfs
1 | void Solution::backtrack(int i) { |
剪枝的dfs
进入下一步遍历之前,检查\(\rm{cw+rest > bestw}\) ,如果剩下的所有加上都小于最优解的话,那么就不用进入了。
1 | /* |