算法与数据结构-贪心算法及背包问题解决

来源:互联网 发布:服务网络占用硬盘 编辑:程序博客网 时间:2024/06/01 08:37

序言

五大常用算法包括:回溯法 + 贪心算法 + 动态规划 + 分治法 + 分支限界法

之前已经介绍过回溯法及其在八皇后问题的应用。本文介绍贪心算法及其常见应用场景。


贪心算法

  • 贪心算法的基本原理
问题求解时,不是从全局最优解来考虑,而是通过求解局部最优解来产生全局最优解或全局最优解的近似解。概念要点:    1. 局部最优解    2. 无后效性,即不可回溯
  • 贪心算法的特性:所求解的问题一般具有两个特性

    • [1] 贪心选择性质:整体最优可以通过一系列局部最优的选择来达到。

      • 贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。
    • [2] 最优子结构性质:一个问题的最优解已经包含了其子问题的最优解。

      • 因此可以依次解决其子问题得到原问题的解
  • 贪心算法的基本思路

    • 建立数学模型
    • 问题分成若干子问题
    • 子问题求解得到子问题的局部最优解(以贪心选择开始)
    • 子问题局部最优合成原问题的一个解
  • 贪心算法使用的要点

    • 问题是否可用贪心算法求解:经验判断,适当证明

      • 贪心算法适用范围窄,很多时候需要根据经验决定是否选择贪心算法
      • 通过数学归纳法进行证明,利用贪心选择性质和最优子结构性质
    • 贪心标准的选择
      • 很重要,标准选择不好很可能导致解题失败
      • 在选择贪心标准时,我们要对所选的贪心标准进行验证才能使用,不要被表面上看似正确的贪心标准所迷惑
  • 与动态规划问题的区别

    • 相似:均通过递推实现,均具有最优子结构性质,均无后效性
    • 区别:
      • 贪心算法每一步的最优解一定包含上一步最优解。上一步最优解不做保留
      • 动态规划全局最优一定包含某个局部最优,但不一定包含前一个局部最优。需要记录之前所有最优解
  • 贪心算法常见应用场景

      1. 公共资源争用的活动安排
        • 教室不同时间段活动安排
      1. 背包问题
        • 不是”0-1背包问题“
      1. 最优装载问题
        • 与背包问题类似
      1. 钱币找零问题
        • 最少纸币张数支付K元


贪心算法应用举例

以背包问题为例简单举例

  • 问题描述

    背包问题:有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

    物品 A B C D E F G
    重量 35 30 60 50 40 10 25
    价值 10 40 30 50 35 40 30

  • 贪心标准

    • [1] 先把价值高的装进去:这样重量消耗太快,不利于总体价值的增长
    • [2] 先把重量小的装进去:这样能保证重量有效增长,但价值不能有效增长
    • [3] 先把价值重量比最大的装进去:按物品权重排序,实现重量和总价值的有效增长
  • 代码(C)

#include <stdio.h>#define true 1#define false 0typedef struct pack_node{    int weight;    int value;    float value2weight;     //价值重量比    char flag;}packNode;int main(){    int Weight[7] = {35, 30, 60, 50, 40, 15, 20};    int Value[7] = {10, 40, 30, 50, 35, 40, 30};    packNode back_pack[7];    int i = 0;    for (; i < 7; i++)    {        back_pack[i].weight = Weight[i];        back_pack[i].value = Value[i];        back_pack[i].flag = false;        back_pack[i].value2weight = (float)((float)(Value[i]) / (float)Weight[i]);    }    int allWeight = 0;    int allValue = 0;    float max = 0.0;        //value / weight最大比值    char markArr[7] = {0};    int j, eleFlag;    float portion;    while (allWeight < 150)    {        j = 0;        max = back_pack[j].value2weight;        while (j < 7)        {            if (back_pack[j].value2weight > max && back_pack[j].flag == false)            {                max = back_pack[j].value2weight;                eleFlag = j;            }            j++;        }        back_pack[eleFlag].flag = true;        allWeight += back_pack[eleFlag].weight;        allValue += back_pack[eleFlag].value;        markArr[eleFlag] = 1;        if (allWeight > 150)        {            portion = (back_pack[eleFlag].weight - (allWeight - 150)) / (float)back_pack[eleFlag].weight;            printf("第%d个物品选取:%.1f\n", eleFlag + 1, portion);        }    }    int k = 0;    printf("取出物品标号如下:");    for (; k < 7; k++)        printf("%d%c",markArr[k], k == 6 ? '\n' : ' ');    return 0;}



Acknowledgements:
http://blog.csdn.net/liufeng_king/article/details/8709005
http://blog.csdn.net/liufeng_king/article/details/8711928
http://blog.csdn.net/qfikh/article/details/51959226
http://blog.csdn.net/qq_23100787/article/details/50490658

2017.09.14

原创粉丝点击