在求解最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最终解,这种求解方法就是贪心算法。
贪心算法所做的选择可以依赖于以往所做过的选择,但绝不依赖于将来的选择,也不依赖于子问题的解。
(1)贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择(即贪心选择)来达到。
(2)最优子结构性质:一个问题的最优解包含其子问题的最优解时。
在对问题求解时,总是做出在当前看来是最好的选择。
(1)不是从整体考虑——得到的解可能不是全局最优
(2)简单,直接,易理解,效率高。
给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量wi ,价值vi(1≤i≤n),要求把物品装满背包,且使背包内的物品价值最大。
其中 wi 为第 i 个物品的重量,xi 取值为1 或 0,表示装入和不装入背包。
(1)首先计算每种物品单位重量的价值 vi / wi ,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
(2)若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。
(3)依此策略一直地进行下去,直到背包装满为止。
有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。
0-1背包问题只有放入和不放入两种情况,且物品不能拆分。
背包问题的物品可以进行拆分。
完全背包问题和0-1背包问题基本一致,但完全背包问题种每个物品可以选择多次。
不能。使用贪心算法不能得到最优解。
主要原因是:由于0-1背包问题无法将物品分割,贪心算法就无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。
举例说明:背包容量为50,n个物品如下
n | 1 | 2 | 3 |
---|---|---|---|
重量 | 10 | 20 | 30 |
价值 | 60 | 100 | 120 |
性价比 | 6 | 5 | 4 |
按照贪心算法的思想,背包容量为50,我们将物品1装入,然后将物品2装入,对物品3进行判断时,由于仅剩20的容量,重量为30的物品3没法装入,因此此时得到的价值为160,剩余20容量的空间闲置;而使用动态规划时,可以得到的最优解为220。
有一批集装箱要装上一艘载重量为c的轮船,其中集装箱 i 的重量为 wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。
输入样例 | 输出样例 |
---|---|
50 3 40 10 40 37 5 10 30 24 35 40 25 3 30 40 50 | 2 1 2 2 1 3 No answer! |
xi 取值为1或0,表示装入和不装入轮船。
按照集装箱重量最轻的先装入轮船。
/*
@author cc
@date 2021/4/19
@Time 10:59
To change this template use File | Settings | File Templates.
最优装载问题
*/
#include
#include "string.h"
#include "algorithm"
using namespace std;
// 定义集装箱的数据结构
struct load{
int index; // 集装箱的编号
int weight; // 集装箱的重量
};
load box[1001]; // 集装箱类型的数组,存储集装箱
int x[1001]; // 用于记录集装箱是否被装入,数组的下标即为集装箱的编号
// 自定义排序因子,按照重量从小到大排序
bool cmp(load a, load b){
if(a.weight < b.weight) return true;
return false;
}
int main(){
int c, n;
cout << "请输入集轮船的载重量c和集装箱的个数n(空格分开):" << endl;
while (cin >> c >> n){ // C/C++中定义EOF为-1 该行语句等同于C中的: while(scanf("%d,%d",&c,&n)!=EOF){
memset(box,0, sizeof(box)); // 将数组box的每个值均初始化为0
memset(x,0, sizeof(x)); // 将数组x的每个值均初始化为0
for (int i = 1; i <= n; ++i) { // i++是先使用i,再让i加1;而++i是先让i加1,再使用i。
// 之所以在for循环中没有影响,是因为我们并没有在i自增的前后使用i,而是执行循环体之后才使用i
cin >> box[i].weight;
box[i].index = i;
}
stable_sort(box,box+n+1,cmp); // 该排序函数与sort区别在于,当有对个相同的元素时,stable_sort不会改变其原有的顺序
if(box[1].weight>c){ // 如果第一个集装箱的重量就大于c则后面的均无法装入
cout << "No answer!";
continue;
}
// 贪心算法的实现,重量最轻者优先装载
int i;
for (i = 1; i <= n && box[i].weight <= c ; i++) {
x[box[i].index] = 1;
c -= box[i].weight; // 每装入一个,c同时减少
}
// 输出装载的集装箱数量
cout << i-1 << endl;
// 输出装载集装箱的编号
for (int j = 1; j <= n; ++j) {
if(x[j]) cout << j << " ";
}
cout <