将最优装载问题的贪心算法推广到2艘船的情形,贪心算法仍能产生最优解吗?

算法分析第五次讨论马上就要到了,我搜索了一下讨论的第一道题目,发现竟然没有详细的解释,没有办法只能自己写了。

翻了一下习题解答,它说见主教材第5章的装载问题。

….

第五章就讲了两艘船的装载问题,他用的是回溯法,因为贪心算法已经不能得到问题的最优解了,所以选择用回溯法来做。其实第五章的问题有了稍许变化,它的要求变成了,是否有一个合理的装载方案,将这n个集装箱装上这2艘船。但我们这个题目说的是将一艘推广到两艘,所以我们就根据最优装载问题中一艘的要求来做,一艘的要求是装尽可能多的箱子。

那为什么最优装载问题的贪心算法,不能推广到两艘船的情形?

因为两艘船的装载问题,是先装完第一艘,再装第二艘,所以就必须把第一艘尽可能的装满,才能使总的装载量更多。如果使用贪心算法求解,第一艘船装载的方式只可能有一种最优解,就是装载的物品都是以从轻到重的顺序装载,所能装的最大重量,那么问题就来了,从轻到重这样装,不一定是最满的。比如{10,20},c1=20,根据贪心算法,它首先装个10上去,然后,就没然后了,就这样结束了,所以它就没有满足尽可能的装满这一条件 。

#include 
#include
using namespace std;

void Loading(int x[], int w[], int c, int n){
	sort(w,w+n);
	for(int i=1;i<=n;i++)
		x[i]=0;		
	for(int i=0;i<=n&&w[i]<=c;i++){
		x[i] = 1;
		c-=w[i];
	}
}

void Loading2(int x[], int w[], int c1, int c2, int n){
	sort(w,w+n);
	for(int i=1;i<=n;i++)
		x[i]=0;
	int i;
	for(i=0;i<=n&&w[i]<=c1;i++){
		x[i] = 1;
		c1-=w[i];
	}
	for(;i<n&&w[i]<=c2;i++){
		x[i] = 1;
		c2 -= w[i];
	}
}

int main(){
	int n=5;
	int c=40;
	int w[5]={10,40,40,80,100};
	int x[n];
	
	Loading(x,w,c,n);
	cout<<"\n一艘船的装载问题:\n";	
	for(int i=0;i<n;i++){
		cout<<x[i]<<"\t";
	}
		
	int c1=100;
	int c2=150;
	int v[6]={30,30,30,50,50,60}; 
	int y[n];
	
	Loading2(y,w,c1,c2,n);
	cout<<"\n两艘船的装载问题:\n";
	for(int i=0;i<n;i++){
		cout<<y[i]<<"\t";
	}
	return 0;
}

如上面的代码,6个元素的数组{30,30,30,50,50,60},容量 C1=100,C2=150.箱子总重量为250,轮船的总容量也为250,按理说最优解应该是所有的箱子都能装上船,

但如果使用贪心算法,会先把30,30,30装到第一艘船,就造成了,10个空间的浪费,导致,会有一个箱子不能装上船。

这也算是反例证明了吧。

而回溯法因为考虑到了所有的装载顺序,所以一定能找到最优的装载方案。

1. 为什么要先装第一艘,再装第二艘?

    是不是有人想会,怎么不两艘轮流着装,我请你吃个棒槌,你见过轮船轮着装集装箱么?就算你不怕麻烦,两艘轮着装,造成的容量浪费可能更加严重。因为贪心算法是从轻到重,那么最坏的情况就是,下一个要装的集装箱刚好大于轮船的剩余容量。如果是一艘船先装,那第一艘的最后一个箱子算中等大小,那第二艘就是终极大小了,比起两艘船一起装所剩的两个终极大箱子的情况要好太多了。加上贪心算法不能推广到两艘船,所以不能用这种方法。

2. 为什么要把第一艘船尽可能的装满?

    先把第一艘船尽可能的装满,是为了第二艘船能放下更多的箱子。

关于两艘船的最优装载问题的回溯法,懒得写了,两种算法的实际对比效果,还是想想得了。

以上纯属个人思考。

有不同想法的,欢迎一起讨论。

—————————————————————————————————————————

再次回顾了一下,发现一些问题:

一艘船的情况下,最优装载能产生最优解?。。。可能没看题目,已经不知道说的是什么了,貌似说的是尽可能多装几个箱子,那还行,一艘船的情况下,从小装到大,装的箱子肯定是最多的,常识常识。但两艘船的情况下,如果使用最优装载,可能会浪费一些空间,导致装得箱子的数量没有回溯法装得那么多。

一句话解决的事情,不知道前面说了那么多废话是干嘛的 = =

前不久参加2018华为的软挑比赛,发现一个很现实的问题,在实际中其实不管使用最优装载还是回溯法或者是01背包,它们的总利用率都是差不多的,因为即使第一艘装得很满了,第二艘少装一点,但仍然需要使用两艘船。甚至可能出现,第一艘非常满,而第二艘,只装了一点的尴尬情况。

要体现出算法优化的效果,我觉得只有当数据量非常大的时候,积少成多,就可能少用几艘船,比如说,有一批货物和若干艘艘船,每艘船能装载的重量为30,假如每艘船使用回溯能比最优装载,多装下 2 的货物,则15艘船才能省下一艘船的开销。但这也只是假想情况,实际处理的时候,还是有很多的不确定性,比如说能省下的空间可能只占0.01%,或者最优装载得到结果本来就是最优了。并且数据量大了,算法的性能会变得很差。

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/qq_30501975/article/details/70197553
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞