我觉得我又行了
回溯法就是深度搜索,但是为了降低搜索的复杂性,用到了剪枝函数去掉了不必要搜索的结点,剪枝函数有两种,一个是约束函数,一个是限界函数。约束函数就是一些约束条件,限界函数就是限制界限即不能产生最优解的函数。
问题描述
有一批共n个集装箱要装上2艘载重量分别为C1和C2的轮船,其中集装
箱i的重量为wi,且∑wi≤C1+C2
装载问题要求确定是否有一个合理的装载方案可将这个集装箱装上这2
艘轮船。如果有,找出一种装载方案。
容易证明,如果一个给定装载问题有解,则采用下面的策略可得到最优装载方案:
(1)首先将第一艘轮船尽可能装满;
(2)将剩余的集装箱装上第二艘轮船。
只需要解决1,2就是确定的了
分析
问题变量
int n; //集装箱个数
int w[100]; //集装箱重量数组
int c; //船的载重量
参数:结点层数t
子集树结点相关数据
int cw; //当前装入集装箱重量
int r; //剩余集装箱的重量
int x[100]; //解向量
记录最优值和最优解的变量
int bestw; //当前最优值
int bestx[100]; //当前最优解
对于每一个集装箱都有两种可能,装或者不装,因为是回溯,所以肯定要遍历所有情况,为了简化复杂度,就需要用到上面说的剪枝函数
约束函数:当该结点放入集装箱,需要考虑当前的重量加上它的重量是否小于等于总载重量,如果是放入,然后以它为扩展结点往下一层扩展。
if (cw + w[i] <= c) //搜索左子树,约束函数
{ x[i] = 1; //第i个集装箱装船
cw += w[i];
backtrack(i + 1); //继续搜索i+1层
cw -= w[i]; }
限界函数:当该结点没有放入集装箱,注意它已经没放入了,所以剩余的重量和放入一样都是之前剩余重量减去当前重量,所以在每次检索的开头都要将剩余重量减去当前重量,最后再加回来。再说回来,如果没加入,需要判当前总重量加上剩余的总重量是否大于当前的最优重量,如果大于,则有可能有更好的解,要不然没有意义,因为哪怕全加入也不会超过当前最优解。
if (cw + r > bestw)
{ x[i] = 0; // 搜索右子树,限界函数
backtrack(i + 1); }