书中的实现思路:
首先书中提出的思想:
如果一个给定的装载问题有解,在采用下面的策略一定可以得到最优的装载方案:
(1)首先将一艘轮船尽可能的装满
(2)然后将剩余的集装箱装上第二艘轮船
根据上述的思想,书中代码实现如下:
实现1:只是单纯的求出c1号仓库最优的装载重量
/*
*出发点是问题一定有解(算法中没考虑无解的情形)
*/
#include<stdio.h>
int n = 3;//物品的数量
int w[4] = {0,40,40,10}; //存放物品的重量,w[0] 不使用
int c1 = 50; //第一个箱子的容量
int c2 = 50; //第二个箱子的容量
int bestw; //记录当前得到的最优的装载重量
int cw; //当前得到的装载重量
void Backtrack(int i);
int main(){
Backtrack(1);
}
void Backtrack(int i){
if (i > n){ //写递归函数,注意首先一定要考虑递归结束的条件
if (cw > bestw){
bestw = cw;
printf("%d ",bestw); //最后一次打印出的bestw为最优的装载重量
}
return;
}
if (cw + w[i] <= c1){ //注意这里不要少了等号!!
cw = cw + w[i];
Backtrack(i+1);
cw = cw - w[i]; //这一步是考虑不装当前的货物w[i],即往当前节点的右子树遍历的时候的情况
}
Backtrack(i+1);
}
实现2:在 实现1 的基础上增加了剪枝函数
增加剪枝函数的实现思想:如果r代表的剩余的没有装的物品的总量,如果r+cw <= bestw ;那么就没有必要再往下面遍历了,于是书中就说可将当前节点Z的右子树减掉去。(其实我一直想为什么不把左子树一起剪去呢?
)

代码:
/*
*书中的出发点是问题一定有解(算法中没考虑无解的情形)
*/
//下面求出c1号仓库最优的装载重量+增加了剪枝函数
#include<stdio.h>
int n = 3;//物品的数量
int w[4] = {0,40,40,10}; //存放物品的重量,w[0] 不使用
int c1 = 50; //第一个箱子的容量
int c2 = 50; //第二个箱子的容量
int bestw; //记录当前得到的最优的装载重量
int cw; //当前得到的装载重量
int r; //记录当前剩余的重量
void Backtrack(int i);
int main(){
for (int i=1;i<=n; i++){
r += w[i];
}
Backtrack(1);
}
void Backtrack(int i){
if (i > n){ //写递归函数,注意首先一定要考虑递归结束的条件
//if (cw > bestw){ 既然增加了剪枝函数,这里的判断就变得多余了
bestw = cw;
printf("%d ",bestw); //最后一次打印出的bestw为最优的装载重量
//}
return;
}
r = r - w[i];
if (cw + w[i] <= c1){ //注意这里不要少了等号!!
cw = cw + w[i];
Backtrack(i+1);
cw = cw - w[i]; //这一步是考虑不装当前的货物w[i],即往当前节点的右子树遍历的时候的情况
}
if (cw + r > bestw){ //剪枝函数
Backtrack(i+1);
}
r += w[i];
}
为了构造最优解,必须在算法中记录与当前最优值相应的当前的最优解。其实也就是使用x[i]记录从根到当前节点的路径; best[i]记录当前最优解
代码:
/*
*书中的出发点是问题一定有解(算法中没考虑无解的情形)
*/
//下面只是单纯的求出c1号仓库最优的装载重量
#include<stdio.h>
int n = 3;//物品的数量
int w[4] = {0,40,40,10}; //存放物品的重量,w[0] 不使用
int c1 = 50; //第一个箱子的容量
int c2 = 50; //第二个箱子的容量
int bestw; //记录当前得到的最优的装载重量
int cw; //当前得到的装载重量
int r; //记录当前剩余的重量
int x[4];
int bestx[4];
void Backtrack(int i);
int main(){
for (int i=1;i<=n; i++){
r += w[i];
}
Backtrack(1);
printf("%d \n",bestw);
for (int i=1; i<=n; i++){
printf("%d", bestx[i]);
}
}
void Backtrack(int i){
if (i > n){ //写递归函数,注意首先一定要考虑递归结束的条件
bestw = cw;
for (int i=1; i<=n; i++){
bestx[i] = x[i];
}
return;
}
r = r - w[i];
if (cw + w[i] <= c1){ //注意这里不要少了等号!!
x[i] = 1; //装入1号箱子
cw = cw + w[i];
Backtrack(i+1);
cw = cw - w[i]; //这一步是考虑不装当前的货物w[i],即往当前节点的右子树遍历的时候的情况
}
if (cw + r > bestw){ //剪枝函数
x[i] = 0; //不装入1号箱子
Backtrack(i+1);
}
r += w[i];
}
代码4:迭代回溯(抽空补上)