vlambda博客
学习文章列表

贪心算法 | 最优装载问题——加勒比海盗船

贪心算法的本质:

 

它是解决问题的策略上“目光短浅”,只根据当前已有信息就做出选择,而且一旦做出选择,不管将来有什么结果,这个结果都不会发生改变。换言之,贪心算法并不是从整体最优考虑,而是在某种意义上的局部最优。注意有时得到的结果并不是最优解,而是最优解的近似解。

 

如何使用贪心算法呢?

 

1)贪心策略

首先要确定贪心策略,选择当前看上去最好的一个方案。例如,挑选苹果,如果你认为个大的是最好的,那你每次都从苹果堆中拿一个最大的,作为局部最优解。贪心策略就是选择当前最大的苹果;再例如另外一种贪心策略是选择当前最红的苹果。因此根据求解目标不同,贪心策略也会不同。

 

2)局部最优解

根据贪心策略,一步一步得到局部最优解。例如,第一次选一个最大的苹果放起来,记为a1,第二次再从剩下的苹果中选择一个最大的苹果放起来,记为a2,以此类推下去。

 

3)全局最优解

把所有的局部最优解合成为原来问题的一个最优解(a1,a2,.....an)

 

贪心算法的应用

 

最常见的冒泡排序就是使用了贪心算法,它的贪心策略就是每一次从剩下的序列中选出一个最大的数,把这些选出来的数按大小排序。


1、最优装载问题——加勒比海盗船

问题:有一天,海盗们截获了一艘装满各种各样的古董的货船,每一件古董都价值连城,一旦打碎就失去了它的价值。虽然海盗船足够大,但载重量为C,每件古董重量为Wi,海盗们该如何把尽可能多数量的宝贝装上海盗船呢?


1.1问题分析

根据问题描述可知这是一个用贪心算法求解得最优装载问题,要求装载的物品的数量尽可能多,但是船的装载能力是有限的。这时可以采用重量最轻的优先装的贪心选择策略。

 

1.2算法设计

1)当载重量为定值c时,Wi越小时,那可装载的数量n就越多。这时就依次选择最小重量的装入,直到不能再装为止。

2)把n个古董从小到大排序,然后根据贪心策略尽可能多选出前i个古董,直到不能装入为止,此时到达最优。

 

1.3图解算法

现在海盗船的载重量c30,而古董重量清单如下表所示:

 

重量W[i]

4

10

7

11

3

5

14

2

 

1)对古董重量按递减排序,如下表所示:

 

重量W[i]

2

3

4

5

7

10

11

14

 

2)按照贪心策略,每次选择重量最小的古董放入(tmp代表古董的重量,ans代表已装个数)

 

i=0,选择排序后的第1个,装入重量tmp=2,不超过载重量30ans=1

i=1,选择排序后的第2个,装入重量tmp=2+3=5,不超过载重量30ans=2

i=2,选择排序后的第3个,装入重量tmp=5+4=9,不超过载重量30ans=3

i=3,选择排序后的第4个,装入重量tmp=9+5=14,不超过载重量30ans=4

i=4,选择排序后的第5个,装入重量tmp=14+7=21,不超过载重量30ans=5

i=5,选择排序后的第6个,装入重量tmp=21+10=31,超过载重量30,算法结束。

 

即放入古董数为5个。

 

1.4伪代码详解

1数据结构定义

根据算法设计描述,我们用一维数组存储古董数量:

double w[N];//一维数组存储古董的重量


 

2按重量排序

 

可以利用C++标准库中的排序函数sort,对古董的重量进行从小到大(非递减)排序。要使用此函数需要引入头文件<algorithm>

语法描述为:

sort(begin, end) //参数beginend表示一个范围,分别为待排序数组的首地址和尾地址
//sort函数默认升序

 

 

在本例中只需要调用sort函数对古董的重量进行从小到大排序:

sort(w, w+n);//按古董重量升序排序


 

3)按照贪心策略找最优解

 

首先用变量ans记录已经装载的古董个数,tmp代表装载到船上的古董的重量,两个变量都初始化为0,然后按照重量从小到大排序,依次检查每一个古董,tmp加上该古董的重量,如果小于等于载重量c,则令ans++;否则,退出。

 double = tmp = 0.0;    int ans = 0;    for (int i = 0; i < n; i++) {        tmp += w[i];        if (tmp <= c) {            ans ++;        } else {            break;        } }