当前位置:文档之家› 算法设计第六章答案

算法设计第六章答案


解空间:深度为 n 完全 m 叉树 两个部件,三个供应商
A
1
2
3
B 1 23
C 1 23
EF G
HI J
D 1 23
KL M
根据条件可知:剪枝函数,约束函数是总价格不超过 d,界限函数是当前扩展结 点的总质量最小值大于当前最优总重量; 优先队列式分支限界法:优先级定义为结点已知部分的总重量;因而,每一次选 择新的扩展结点都是选择已知部分总重量最小的结点,因而界限函数可以省略; 算法流程: 主函数是一个 while 循环,结束条件是当前扩展结点的深度是 n,因为是优先队 列式分支限界(每一次都选择当前最小重量的结点作为扩展结点),因而第一个 找到的叶结点肯定是最优解; 每一次循环所需要完成的工作包括:1)将扩展结点的所有儿子结点加至活结点 列表中;其中,需要利用约束函数进行剪枝;2)按照“先进先出”原则,选择 下一个扩展结点。
活结点列表

为空?


当前扩展结点 在排列树中的深度
是n-1?

将当前扩展结点的儿子结点 分别加至活结点列表
输出最优解 结束

所有儿子结点
都已经得到判断?

选择下一个儿子结点,并且计 算各连接块的最大长度
各连接块的 当前最大长度小于当前

最优长度?

将当前儿子结点加至 活结点列表
将儿子结点加至活 结点列表
开始 根结点加入活结点列表,
并作为当前扩展结点
活结点列表

为空?

将当前扩展结点的儿子结点 分别加至活结点列表
左儿子结点

满足容量约束?

将左儿子结点加至 活结点列表
右儿子结点的 最大价值大于当前

最优价值?

将右儿子结点加至 活结点列表
按照“后进先出”,选择下 一个扩展结点
输出最优解 结束
将儿子结点加至活 结点列表
if(ok(r,c,board[r][i])) { Swap(board[r][c],board[r][i]); if(c==n) { if(r==m) count+=1.0; else Backtrace(r+1,2); } else Backtrace(r,c+1); Swap(board[r][c],board[r][i]); } }
解空间:对于每一行而言,是一个深度为 n 的排列树;因而,整个空间是 m 个 深度为 n 的排列树。 剪枝函数:每一列上的 m 个元素存在重复。 因而,这个问题存在两个有关深度的变量 r(行)和 c(列),即 Backtrace(r,c)
void Backtrace(int r,int c) { for(int i=c;i<=n;i++)
按照“先进先出”原则,选 择下一个扩展结点
开始
根结点加入活结点列表, 并作为当前扩展结点
当前扩展结点在解 是 空间数的深度是n?
否 将当前扩展结点的儿子结点
分别加至活结点列表

所有儿子结点
都已经得到判断?

选择下一个儿子结点,并且计算 当前儿子结点的总重量和总价格
当前儿子结点的

当前总价格小于d?
算法流程: 主函数是一个 while 循环,结束条件是活结点列表为空,表示所有叶结点都已经 遍历完成;此时,应该输出整个问题的最优解。 每一次循环需要完成的工作包括:1)如果当前扩展结点的深度是 n-1计算每一个连接块的长度,并且计算所有连接块的 最大长度;2)如果当前深度小于 n-1,则需要将扩展结点的儿子结点加至活结点 列表;其中,需要利用界限函数进行剪枝(界限函数就是各连接块的当前最大长 度小于当前最优长度);3)按照“先进先出”原则,选择下一个扩展结点。
设计一个解 01 背包问题的栈式分支限界法,并说明栈式分支限界法与回溯法的 区别。
解空间:子集树
A
1
0
B
1
0
C
1
0
D
E
F
G
1)队列式分支界限法和栈式分支界限法对比: 队列式分支限界法活结点列表变化过程:(先进先出)
1{A} 2{B,C} 3{C,D,E} 4{D,E,F,G} 5{E,F,G} 6{F,G} 7{G} 8{}
1
B
2
3
E
F
3
2
K
L
A 2
C
1
3
3
D
1
2
G
H
I
J
3
1
2
1
M
NO
P
注意:与课本例题最小密度电路板排列问题不同,在每一次将当前扩展结点的儿 子结点加至活结点列表时(当深度加 1 时),应该更新和计算儿子结点的当前最 小长度; 对于每一个结点而言,需要维护两个数组,low[1:m]和 high[1:m],分别记录着每 一个连接块的当前已知的起点插槽序号和终点插槽序号,当深度增加 1 时,首先 判断连接块 Nj 是否需要跨越 x[i+1]所对应的电路板; 假设 x[1:i]已知,x[i+1]是当前儿子结点所对应的第 i+1 层元素取值,则数组 low 和 high 更新方法是: 1) 如果连接块 Nj 跨越 x[i+1]电路板,而且当前 low[j]大于 i+1,则将 low[j]更新
算法实现题 6-4: 最小重量机器设计问题 问题描述:设某一个机器由 n 个部件组成,每一种部件都可以从 m 个不同的供 应商处购得。设 wij 是从供应商 j 处购得的部件 i 的重量,cij 是相应的价格。 设计一个优先队列式分支限界法,给出总价格不超过 d 的最小重量机器设计。 编程任务: 对于给定的机器部件重量和机器部件价格,设计一个优先队列式分支限界法,计 算总价格不超过 d 的最小机器设计。

将当前儿子结点加至 活结点列表
输出最优解 结束
将儿子结点加至活 结点列表
为 i+1; 2) 如果连接块 Nj 跨越 x[i+1]电路板,而且当前 high[j]小于 i+1,则将 high[j]更
新为 i+1; 3) 其余情况,则不需要更新 low[j]和 high[j]。
开始
根结点加入活结点列表, 并作为当前扩展结点
按照“先进先出”,选择下 一个扩展结点
计算各连接块的最小长度, 并且更新当前最优长度
2)程序流程 整个流程与队列式分支限界法的 01 背包问题一样,只是插入活结点的操作:由 insert()改为 push(),重新选择下一个扩展结点的操作:由 delete()改为 pop()。 算法主函数是: 一个 while(1)循环,循环结束条件是活结点列表为空,即当前扩展结点为空,表 示所有可行的结点都已经得到遍历;并且输出最优解。 每一次循环作用是:在当前的扩展结点下,将以当前扩展结点作为父结点的下一 层子结点都加入到活结点列表里,并且选择一个新的扩展结点,进入下一层循环; 其中,剪枝函数包括左结点的容量约束(约束函数)和右结点的最大价值判断(界 限函数);
算法实现题 6-1:最小长度电路板排列问题 问题描述:最小长度电路板排列问题是大规模电子系统设计中提出的实际问题。 该问题的提法是,将 n 块电路板以最佳排列方案插入带有 n 个插槽的机箱中。n 块电路板的不同排列方式对应与不同的电路板插入方式。 设 B={1,2,···,n}是 n 块电路板的集合。集合 L={N1,N2,···,Nm}是 n 块电 路板的 m 个连接块。其中,每个连接块 Ni 是 B 的一个子集,且 Ni 中的电路板 用同一根导线连接在一起。 在最小长度电路板排列问题中,连接块的长度是指该连接块中第一块电路板到最 后一块电路板之间的距离; 试设计一个队列式分支界限法找出所给 n 个电路板的最佳排列,使得 m 个连接 块中最大长度达到最小。 解空间:排列树
算法实现题 5-9:拉丁矩阵问题 问题描述:现有 n 种不同形状的宝石,每种宝石有足够多颗。欲将这些宝石排列 成 m 行 n 列的一个矩阵,m<=n,使矩阵中每一行和每一列的宝石都没有相同形 状。试设计一个算法,计算出对于给定的 m 和 n,有多少中不同的宝石排列方案。 即,给定一个 m*n 大小的矩阵,每一行 n 个元素是 1~n 的一种排列, 拉丁矩阵要求每一列上的 m 个元素不能够有重复。
栈式分支限界法活结点列表变化过程:(后进先出)
1{A} 2{B,C} 3{B,F,G} 4{B,F} 5{B} 6{D,E} 7{D} 8{} 从各结点的扩展次序来讲,队列式分支限界法是标准的宽度优先,栈式分支限界 则类似于深度优先。 回溯法: 各结点的遍历次序是:
A->B->D->B->E->A->C->F->C->G 回溯法是深度优先,而且结点 A,B,C 都两次成为扩展结点; 但是,栈式分支限界法各结点只有一次机会成为扩展结点。
其中,第一个 for 循环:同一深度上的各子结点扩展;ok 函数是剪枝函数; 如果不考虑“行 r”,并且去掉红色方框中的代码,则整个回溯函数跟排列树形式 的代码框架一样;其中,红色部分主要是针对“行 r”进行递归(深度加 1)。
习题 6.1:01 背包问题的栈式分支限界法 栈式分支限界法将活结点表以后进先出(LIFO)的方式存储于一个栈中。试
相关主题