zoukankan      html  css  js  c++  java
  • 1-2、算法设计常用思想之贪婪法

    文章内容来自王晓华老师

    贪心算法,是寻找最优解问题的常用方法
    这种方法模式一般将求解过程分成若干个步骤,但每个步骤都应用贪心原则,选取当前状态下最好的或最优的选择(局部最有利的选择),并以此希望最后堆叠出的结果也是最好或最优的解。
    因为不进行回溯处理,贪婪法只在很少的情况下可以得到真正的最优解,比如最短路径问题、图的最小生成树问题。
    在大多数情况下,由于选择策略的“短视”,贪婪法会错过真正的最优解,而得不到问题的真正答案。但是贪婪法简单、高效,省去了为找最优解可能需要的穷举操作,可以得到与最优解比较接近的近似最优解,通常作为其他算法的辅助算法来使用。

    贪婪法的基本设计思想有以下三个步骤:
    • 建立对问题精确描述的数学模型,包括定义最优解的模型;
    • 将问题分解为一系列的子问题,同时定义子问题的最优解结构;
    • 应用贪心原则确定每个子问题的局部最优解,并根据最优解的模型,用子问题的局部最优解堆叠出全局最优解。

    背包问题:有 N 件物品和一个承重为 C 的背包(也可定义为体积),每件物品的重量是 wi,价值是 pi,求解将哪几件物品装入背包可使这些物品在重量总和不超过 C 的情况下价值总和最大。
    背包问题(Knapsack Problem)是此类组合优化的NP完全问题的统称,如货箱装载问题、货船载物问题等,因问题最初来源于如何选择最合适的物品装在背包中而得名,这个问题隐含了一个条件,每个物品只有一件,也就是限定每件物品只能选择 0 个或 1 个,因此又被称为 0-1 背包问题

    实例

      有一个背包,最多能承载重量为 C=150 的物品,现在有 7 个物品(物品不能分割成任意大小),编号为 1~7,重量分别是 wi=[35,30,60,50,40,10,25],价值分别是 pi=[10,40,30,50,35,40,30],现在从这 7 个物品中选择一个或多个装入背包,要求在物品总重量不超过 C 的前提下,所装入的物品总价值最高。

    思路

      常见的贪婪策略有三种:第一种策略是根据物品价值选择,每次都选价值最高的物品,此时包中物品总重量是 130,总价值是 165。第二种策略是根据物品重量选择,每次都选择重量最轻的物品,此时包中物品总重量是 140,总价值是 155。第三种策略是定义一个价值密度的概念,每次选择都选价值密度最高的物品,物品的价值密度 si 定义为 pi/wi,此时包中物品的总重量是 150,总价值是 170,我们可以选用合适的策略,得到较优解

    通用的解题思路

    /**GreedyAlgo() 函数是贪婪算法的主体结构,包括子问题的分解和选择策略的选择都在这个函数中。
    能够明显看出来这个算法使用了迭代法的算法模式,当然,这个算法主体的实现还可以使用递归法,
    正如函数所展示的那样,它可以作为此类问题的一个通用解决思路:
    */ void GreedyAlgo(KNAPSACK_PROBLEM *problem, SELECT_POLICY spFunc) { int idx; int ntc = 0; //spFunc 每次选最符合策略的那个物品,选后再检查 while((idx = spFunc(problem->objs, problem->totalC - ntc)) != -1) { //所选物品是否满足背包承重要求? if((ntc + problem->objs[idx].weight) <= problem->totalC) { problem->objs[idx].status = 1; ntc += problem->objs[idx].weight; } else { //不能选这个物品了,做个标记后重新选 problem->objs[idx].status = 2; } } PrintResult(problem->objs); } /**spFunc 参数是选择策略函数的接口,通过替换这个参数,可以实现上文提到的三种贪婪策略,
    分别得到各种贪婪策略下得到的解。以第一种策略为例,每次总是选择 price 最大的物品,可以这样实现:
    */ int Choosefunc1(std::vector<OBJECT>& objs, int c) { int index = -1; //-1表示背包容量已满 int mp = 0; for(int i = 0; i < static_cast<int>(objs.size()); i++) { if((objs[i].status == 0) && (objs[i].price > mp)) { mp = objs[i].price; index = i; } } return index; }

    lua代码实现

    -- 物品
    -- obj = {
    --     weight = 0,
    --     price = 0,
    --     status = 0  -- 0未选中  1已选中 2已不可选
    -- } 
    
    -- 背包
    -- bag = {
    --     obj_list = {},
    --     totalC = 0
    -- }
    
    local function choose_func1(obj_bag, use_c)
        local index = -1  ---1表示背包容量已满
        local mp = 0
        for i = 1, #obj_bag.obj_list do
            if((obj_bag.obj_list[i].status == 0) and obj_bag.obj_list[i].price > mp) then
                mp = obj_bag.obj_list[i].price
                index = i
            end
        end
        return index
    end
    
    local function greedy_algo(bag, spFunc)
        local idx = nil
        local ntc = 0 -- 已用重量
        idx = spFunc(bag, ntc)
        while(idx ~= -1) do
            if(ntc + bag.obj_list[idx].weight) <= bag.totalC then
                bag.obj_list[idx].status = 1
                ntc = ntc + bag.obj_list[idx].weight
            else
                bag.obj_list[idx].status = 2
            end
            idx = spFunc(bag, ntc)
        end
        print("==============11111")
        dump(bag.obj_list)
    end
    
    local bag_1 = {
        obj_list = {
            {weight = 10, price = 10, status = 0},
            {weight = 20, price = 20, status = 0},
            {weight = 30, price = 40, status = 0},
            {weight = 40, price = 30, status = 0},
            {weight = 50, price = 50, status = 0},
            {weight = 60, price = 70, status = 0},
        },
        totalC = 150
    }
    
    greedy_algo(bag_1, choose_func1)

    总结

    贪婪法只能得到比较接近最优解的近似最优解,但是作为一种启发式辅助方法在很多算法中都得到了广泛的应用,很多常用的算法在解决局部最优决策时,都会应用到贪婪法。比如 Dijkstra 的单源最短路径算法在从 dist 中选择当前最短距离的节点时,就是采用的贪婪法策略。事实上,在任何算法中,只要在某个阶段使用了只考虑局部最优情况的选择策略,都可以理解为使用了贪婪算法。

  • 相关阅读:
    Hadoop的运行痕迹
    生活常识
    hadoop集群崩溃恢复记录
    Hadoop_NameNode_代码分析_目录树(2)
    .NET Is 和 As 的区别
    hadoop集群管理之 SecondaryNameNode和NameNode
    sql2005分页存储过程原创
    c#生成json数据 JavaScript对json数据处理
    LVS改变ConnectionHashtable值
    MySQL Cluster集群配置
  • 原文地址:https://www.cnblogs.com/orxx/p/10940389.html
Copyright © 2011-2022 走看看