您的位置:首页 > 其它

装载问题(2) --课本实现

2016-07-22 10:12 281 查看
书中的实现思路:
首先书中提出的思想:
如果一个给定的装载问题有解,在采用下面的策略一定可以得到最优的装载方案:
(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];

}


实现3  在实现2的基础上 构造最优解
为了构造最优解,必须在算法中记录与当前最优值相应的当前的最优解。其实也就是使用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:迭代回溯(抽空补上)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法