450 likes | 611 Views
Chapter17 分支定界. 与回溯算法的比较 17.1 分支定界的思想 17.2 算法的应用 货箱装船: FIFO 、最大收益 旅行商问题:最小耗费. 分支定界 VS. 回溯算法. 相同点: 都使用树形结构(子集树或排列树)来组织解空间 不同点: 回溯算法使用 DFS 方法来搜索树; 分支定界使用 BFS 方法或 最小耗费 方法来搜索树 分支定界的解空间比回溯算法要大得多 当内存容量有限时,回溯法更易成功! 但有时候,分支定界能够找到最优解。. 1 、算法的思想. 对 E- 节点的扩充方式:引入 活节点表
E N D
Chapter17分支定界 • 与回溯算法的比较 • 17.1 分支定界的思想 • 17.2 算法的应用 • 货箱装船:FIFO、最大收益 • 旅行商问题:最小耗费
分支定界 VS. 回溯算法 • 相同点: • 都使用树形结构(子集树或排列树)来组织解空间 • 不同点: • 回溯算法使用DFS方法来搜索树; • 分支定界使用BFS方法或最小耗费方法来搜索树 • 分支定界的解空间比回溯算法要大得多 • 当内存容量有限时,回溯法更易成功! • 但有时候,分支定界能够找到最优解。
1、算法的思想 对E-节点的扩充方式:引入活节点表 【思想】每个活节点有且仅有一次机会变成 E-节点。当一个节点变为E-节点时,则生成从该节点移动一步即可到达的所有新节点。在生成的节点中,抛弃那些不可能导出(最优)可行解的节点,其余节点加入活节点表,然后从表中选择一个节点作为下一个E-节点。 从活节点表中取出所选择的节点并进行扩充,直到找到解或活动表为空,扩充过程才结束。
选择E-节点的方法 • 先进先出:活节点表的性质与队列相同 • 最小耗费或最大收益:每个节点都有一个对应的耗费或收益 • 查找一个具有最小耗费的解,则活节点表可用最小堆来建立 • 搜索一个具有最大收益的解,则活节点表可用最大堆来构造活节点表 • 下一个 E-节点就是满足条件的活节点
(1,2) (2,1) (1,3) (2,1) (1,3) (3,1) 示例1:迷宫老鼠问题 E-节点 活节点表 Step1:(1,1) Step2:(1,2) Step3:(2,1) Step4:(1,3) (3,1) Step5:(3,1) (3,2) Step6:(3,2) (3,3) Goal:(3,3) NULL
E F G F B C G C E 示例2:0/1背包问题 • n=3, w=[20,15,15], p=[40,25,25], c=30 • FIFO分支定界 E-节点 活节点表 A B C E 解1:[1,0,0], 收益40 F G 解2:[0,1,1], 收益50 NULL G
FIFO分支定界法小结 • 对于迷宫问题,FIFO法总能找到从入口到出口的最短路径;而回溯法却不能保证 • 在解空间树上的FIFO法,类似从根节点出发的BFS方法; • 与BFS的区别在于:在FIFO分支定界中,不可行的节点不会被搜索!
最大收益-分支定界思想 • 使用一个最大堆:其中的 E-节点按照每个活节点收益值的降序,或是按照活节点任意子树的叶节点所能获得的收益估计值的降序从队列中取出
F G B E C C 再解示例2:最大收益法 • n=3, w=[20,15,15], p=[40,25,25], c=30 E-节点 活节点表 A B E C 解1:[1,0,0], 收益40 C F G 解2:[0,1,1], 收益50 G NULL
最大收益-分支定界小结 • 定界函数确定最大收益的上限;如果一个节点的定界函数值不大于目前最优解的收益值,则此节点会被删除而不作为E-节点展开 • 节点取出策略:使节点按照它们收益的定界函数值的非升序从最大堆中取出;这种策略从可能到达一个好的叶节点的活节点出发,而不是从目前具有较大收益值的节点出发
C D E D F G E H F I G J K 示例3:旅行商问题 • FIFO分支定界 E-节点 活节点表 B C E 路径12341,59 F 路径12431,66 G 路径13241,25 H 路径1342,不展开 I 路径14231,25 J 路径1432,不展开 K
E D H D J J K K C C I C 再解示例3:最小耗费法 • 使用最小堆存储活节点 E-节点 活节点表 B E D 路径13241,25 H 【定界函数】如果一个节点的定界值不比当前最优旅行更小,则将被删除而不被展开!
最小耗费-分支定界小结 • 定界函数确定最小耗费的下限;如果一个节点的定界值不比当前最优旅行更小,则将被删除而不被展开 • 节点取出策略:使节点按照它们耗费的定界函数值的非降序从最小堆中取出
分支定界法-小结 • 设计定界函数的原则:利用最少的时间,在内存允许范围内去解决问题 • 好的定界函数:一个能够有效地减少计算时间,并因此使产生的节点数目也减少 • 通过产生具有最少节点的树来解决问题并不是根本的目标
分支定界法 VS. 回溯法 • 分支定界法在直觉上好于回溯法,在寻找最优解的许多情况下,可能会比回溯法检查更少的节点 • 但是,回溯法比分支定界在占用空间方面更具优势:回溯法是O(解空间的最大路径长度);分支定界是O(解空间大小) • 子集树:O(2n)VS. O(n) • 排列树:O(n!)VS. O(n)
课后练习 • Page519:练习2,0/1背包问题 • 1) 绘制n=4时,解空间树 • 2) 描述FIFO -分支定界过程 • 4) 描述最大收益-分支定界过程
2、算法的应用 • 货箱装船问题:子集树 • FIFO分支定界 • 最大收益分支定界 • 旅行商问题:排列树 • 最小耗费分支定界
(1)货箱装船问题 • 1)FIFO分支定界 • Page519:程序17-1 • 注意:队列权值-1,标识活节点表的结尾 • AddLiveNode可能会失败!需处理异常 • 时间和空间复杂度: O(2n)
队列权值-1,标识 每层活节点的结尾
FIFO分支定界的优化 • 目的:当右孩子对应的重量加上剩余货箱的重量超出 bestw时,才选择右孩子 • 问题:在i变为n之前, bestw的值一直保持不变,因此在i等于n之前对右孩子的测试总能成功 • 解决方法:应当提早改变 bestw的值,即:由于仅在向左子树移动时最优装载重量才会增大,因此可以在每次进行这种移动时改变 bestw的值 • Page521:程序17-2
寻找最优子集 • FIFO分支定界寻找最优子集:记录从每个活节点到达根的路径 • 在找到最优装载所对应的叶节点之后,就可以利用所记录的路径返回到根节点来设置 x 的值
定义活节点队列中元素类型 template<class T> class QNode { …… private: QNode *parent; // 指向父节点的指针 bool LChild; // 当且仅当是父节点的左孩子时,为true T weight; //由到达本节点的路径所定义的部分解的值 };
注意:程序未删除类型为QNode的节点。 为了删除这些节点,可以保存由这些 节点的指针,以便在程序结束时 删除这些节点。
(2)最大收益-分支定界 • 活节点列表是一个最大优先级队列,其中每个 活节点x都有一个相应的重量上限(最大收益)。这个重量上限是节点x相应的重量加上剩余货箱的总重量,所有的活节点按其重量上限的递减顺序变为 E-节点 • 【结论1】如果节点x 的重量上限是x .uweight,则在子树中不可能存在重量超过x.uweight的节点 • 【结论2】:当某个叶节点成为E-节点并且其他任何活节点都不会帮助我们找到具有更大重量的叶节点时,最优装载的搜索终止
最大收益-实现方法 • 【方法一】最大优先级队列中的活节点都是互相独立的,因此每个活节点内部必须记录从子集树的根到此节点的路径。一旦找到了最优装载所对应的叶节点,就利用这些路径信息来计算 x 值。 • 【方法二】除了把节点加入最大优先队列之外,节点还必须放在另一个独立的树结构中,这个树结构用来表示所生成的子集树的一部分。当找到最大装载之后,就可以沿着路径从叶节点一步一步返回到根,从而计算出 x 值。
基于方法二的最优装载 • 使用最大堆来表示活节点的最大优先队列时,需要预测这个队列的最大长度。可以使用一个基于指针的最大优先队列来取代基于数组的队列 • 注意剩余重量数组r: • r[n] = 0 • r[n-1] = r[n]+w[n] • r[n-2] = r[n-1]+w[n-1] • … • r[1] = r[2]+w[2]
活节点的 重量上限 当前E节点的 重量
算法的改进思想 • 【问题】bestw表示当前所有可行节点的重量的最大值,而优先队列中可能有许多其uweight不超过bestw的活节点,因此这些节点不可能帮助我们找到最优的叶节点,所以可以将这些节点删除 • 【解决】bestw在算法执行过程中是不断增大的,在每次bestw增大时,删除队列中所有uweight < bestw的节点。这种策略要求删除具有最小uweight的节点。 • 【可引入】双端优先队列(第9章的参考文献)
(2)旅行商问题 • 解空间是排列树 • 方法一:只使用一个优先队列,队列中的每个元素中都包含到达根的路径 • 方法二:是保留一个部分解空间树和一个优先队列,优先队列中的元素并不包含到达根的路径
MinHeapNode template<class T> class MinHeapNode { friend AdjacencyWDigraph<T>; public: operator T () const {return lcost;} private: T lcost, //该节点子树中任意叶节点中的最小耗费 cc, //解空间树中从根节点到当前节点的耗费 rcost; //从顶点x[s:n-1]出发的所有边的最小耗费之和 int s, //当前旅行路径x[0:s], //剩余待访问的节点是x[s+1: n-1] *x; //从1到n 的整数排列,其中x[0]=1 };
计算有向图中从每个顶点出发的边中耗费最小的边所具有的耗费MinOut 计算有向图中从每个顶点出发的边中耗费最小的边所具有的耗费MinOut • 如果有向图中存在某些顶点没有出边,则搜索停止,说明图中没有旅行路径
BBTSP(续1) • MinSum:累计所有顶点发出边的最小耗费之和 • 初始E节点为根的孩子,x[0]=1
边(x[n-2],x[n-1]) 边(x[n-1],x[1]) 当某个叶节点成为 E-节点 后,搜索过程即终止 s=n-2的E-节点,这时E-节点是某个单独叶节点的父节点
待检查边(x[s],x[i]) x[i]是x[s+1..n-1]上顶点 cc表示当前孩子节点的路径 前缀(x[0:s],x[i])的耗费 后续孩子节点筛选标准: cc+各剩余顶点的出边耗费 的最小值之和。
BBTSP(续3) • 返回最优旅行路径的耗费bestc,及最优路径顶点序列数组v
本章小结 • 与回溯算法的比较 • 分支定界的思想 • 分支定界的应用 • 货箱装船:FIFO分支、最大收益 • 旅行商问题:最小耗费
课后练习 • Page519:练习2的1)、2)、4) • 提高篇: • Page535:练习23,FIFO分支定界实现 8-皇后问题