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

书中的实现思路:
首先书中提出的思想:
如果一个给定的装载问题有解,在采用下面的策略一定可以得到最优的装载方案:
(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:迭代回溯(抽空补上)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值