当前位置:   article > 正文

算法设计与分析——贪心算法_关于贪心算法的论文

关于贪心算法的论文

1. 贪心算法

1.1 定义

在求解最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最终解,这种求解方法就是贪心算法。

贪心算法所做的选择可以依赖于以往所做过的选择,但绝不依赖于将来的选择,也不依赖于子问题的解。

1.2 基本要素

(1)贪心选择性质:所求问题的整体最优解可以通过一系列局部最优的选择(即贪心选择)来达到。

(2)最优子结构性质:一个问题的最优解包含其子问题的最优解时。

1.3 基本思想

在对问题求解时,总是做出在当前看来是最好的选择。

1.4 特点

(1)不是从整体考虑——得到的解可能不是全局最优

(2)简单,直接,易理解,效率高。

2. 典型案例

2.1 背包问题(物品可分割)

2.1.1 问题描述

给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量wi ,价值vi(1≤in),要求把物品装满背包,且使背包内的物品价值最大。

2.1.2 问题转换

image-20210609092145445

其中 wi 为第 i 个物品的重量,xi 取值为1 或 0,表示装入和不装入背包。

2.1.3 问题求解步骤

(1)首先计算每种物品单位重量的价值 vi / wi ,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。

(2)若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。

(3)依此策略一直地进行下去,直到背包装满为止。

2.2 背包问题与0-1背包问题的区别

有两类背包问题(根据物品是否可以分割),如果物品不可以分割,称为0—1背包问题(动态规划);如果物品可以分割,则称为背包问题(贪心算法)。

  • 0-1背包问题只有放入和不放入两种情况,且物品不能拆分。

  • 背包问题的物品可以进行拆分。

  • 完全背包问题和0-1背包问题基本一致,但完全背包问题种每个物品可以选择多次。

2.3 贪心算法可以求解背包问题,那么能不能用贪心算法求解0-1背包问题?若不能,为什么?去反例说明。

不能。使用贪心算法不能得到最优解。

主要原因是:由于0-1背包问题无法将物品分割,贪心算法就无法保证最终能将背包装满,部分闲置的背包空间使每公斤背包空间的价值降低了。

举例说明:背包容量为50,n个物品如下

n123
重量102030
价值60100120
性价比654

按照贪心算法的思想,背包容量为50,我们将物品1装入,然后将物品2装入,对物品3进行判断时,由于仅剩20的容量,重量为30的物品3没法装入,因此此时得到的价值为160,剩余20容量的空间闲置;而使用动态规划时,可以得到的最优解为220。

image-20210609100128868

2.4 最优装载问题

2.4.1 问题描述

有一批集装箱要装上一艘载重量为c的轮船,其中集装箱 i 的重量为 wi。最优装载问题要求确定在装载体积不受限制的情况下,将尽可能多的集装箱装上轮船。

输入样例输出样例
50 3 40 10 40 37 5 10 30 24 35 40 25 3 30 40 502 1 2 2 1 3 No answer!

2.4.1 问题转化

image-20210609100519385

xi 取值为1或0,表示装入和不装入轮船。

2.4.2 贪心选择策略

按照集装箱重量最轻的先装入轮船。

2.4.2 代码实现

/*
    @author cc
    @date 2021/4/19
    @Time 10:59
    To change this template use File | Settings | File Templates.
    最优装载问题
*/
#include<iostream>
#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 <<endl;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/967185
推荐阅读
相关标签
  

闽ICP备14008679号