贪心算法之背包问题

贪婪算法的基本思想:通过一系列步骤来构造问题的解,每一步都是对已构造的部分解的一个扩展,直到获得问题的完整解。

贪婪算法中,每一步“贪婪地” 选择最好的部分解,但不顾及这样选择对整体的影响(局部最优),因此得到的全局解不一定最好的解,但对许多问题它能产生整体最优解。

具体算法描述:

public static void Greedy()
        {
            float cu = c;
            int temp = 0;
            int i = 0;
            for (i = 0; i < n; ++i )
            {
                x[i] = 0;//初始化为0
            }
            for (i = 0; i < n; ++i )
            {
                temp = sortResult[i];//得到取物体的顺序

if (w[temp] > cu)
                {
                    break;
                }
                //将物品装入背包
                x[temp] = 1;
                cu -= w[temp];//背包容量相应减小

}
            if (i <= n)//使背包充满
            {
                x[temp] = cu / w[temp];// 比如背包容量剩余10,w[temp] = 9.8f; 要装满
            }

Display();
        }

贪婪算法每一步需要满足3个条件:

1.可行性:即必须满足问题的约束。

2.局部最优:它是当前步骤中所有可行选择中最佳的局部选择。

3.不可取消:选择一旦做出,在后面的步骤中就无法改变。

贪心算法的基本要素:

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

2.最优子结构性质:指一个问题的最优解包含其子问题的最优解。

贪心算法与动态规划算法的异同:

相同点:都具有最优子结构性质。

不同点:动态规划算法通常以自底向上的方式解各子问题;而贪心算法则通常以自顶向下的方式进行;

下面研究2个经典的组合优化例题,并以此说明贪心算法与动态规划算法的主要差别。

0-1背包问题:

给定n种物品和一个背包。物品i的重量是Wi,其价值为Vi,背包的容量为C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

背包问题:
与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n。

这2类问题都具有最优子结构性质,极为相似;但背包问题可以用贪心算法求解;而0-1背包问题却不能用贪心算法求解。

对于0-1背包问题:

例:n=3 , w={10,20,30} ,v={60,100,120} ,c=30
  什么是最好的部分解?  ——不求单位价值。
  按贪心法:选择价值最大的放入 : 全部放入第3个物品,价值120。
  但这并不是最好的, 若1,2 物品的放入,总价值160。

对于背包问题:

例:n=3 w={10,20,30} v={60,100,120} c=50
单位价值:v/w={6,5,4}
因此,第一次挑一号物品全部装入, r=40,pv=60
第二次挑2号,全部装入r=20,pv=160
第三次挑3号,部分装入r=0,pv=160+80=240

具体代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SeqListSort
{
    /// <summary>
    /// <ather>
    /// lihonlgin
    /// </ather>
    /// <content>
    /// 背包问题:
    ///与0-1背包问题类似,所不同的是在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装
    ///入背包,1≤i≤n。
    ///这2类问题都具有最优子结构性质,极为相似;但背包问题可以用贪心算法求解;
    ///而0-1背包问题却不能用贪心算法求解。
    /// </content>
    /// </summary>
    class Greedy_Knapsack
    {
        const int size = 20;
        static float[] w = new float[size];
        static float[] v = new float[size];
        static int n = 5;// 十个物品
        static int c = 20;//背包容量
        static float[] x = new float[size];
        static int[] sortResult = new int[size];//保存单位价值从大到小的下标

        public static void InitData()
        {
            Random r = new Random();
            for (int i = 0; i < n; ++i )
            {
                v[i] = r.Next(10, 31);
                w[i] = r.Next(5, 16);
                x[i] = v[i] / w[i];
                Console.Write("重量为:{0:f2} ", w[i]);
                Console.WriteLine("价值为:{0:f2} ", v[i]);
            }
            Console.WriteLine();
            Sort();// 先排序
        }

        static void Sort()
        {
            float temp = 0.0f;
            int index = 0;
            int k = 0;
            for (int i = 0; i < n-1; ++i )
            {
                temp = x[i];
                index = i;
                //找到最大的效益并保存此时的下标
                for (int j = i+1; j < n; ++j )
                {
                    if (temp < x[j] && (0 == sortResult[j]))
                    {
                        temp = x[j];//第一趟比较得到最大值
                        index = j;//标记下标
                    }
                }
                //对w[i]作标记排序
                if ( 0 == sortResult[index] )
                {
                    sortResult[index] = k++;
                }
            }
            //修改效益最低的sortResult[i]标记
            for (int i = 0; i < n; i++)
            {
                if (0 == sortResult[i])
                {
                    sortResult[i] = k++;
                }
            }

        }

        public static void Greedy()
        {
            float cu = c;
            int temp = 0;
            int i = 0;
            for (i = 0; i < n; ++i )
            {
                x[i] = 0;//初始化为0
            }
            for (i = 0; i < n; ++i )
            {
                temp = sortResult[i];//得到取物体的顺序

                if (w[temp] > cu)
                {
                    break;
                }
                //将物品装入背包
                x[temp] = 1;
                cu -= w[temp];//背包容量相应减小

            }
            if (i <= n)//使背包充满
            {
                x[temp] = cu / w[temp];// 比如背包容量剩余10,w[temp] = 9.8f; 要装满
            }

            Display();
        }

        static void Display()
        {
            for (int i = 0; i < n; ++i )
            {
                Console.Write("编号:" + i);
                Console.WriteLine("  物品放入的数量{0:F}  ", x[i]);
            }
            Console.WriteLine();
        }
    }
}
时间: 2024-10-25 09:35:42

贪心算法之背包问题的相关文章

数据结构之贪心算法(背包问题的思考)-(十)

贪心策略.关于贪心算法的思考,思考过程都放在代码中了. package com.lip.datastructure; /** *贪心算法:装箱问题的思考 * @author Lip *装箱问题可以是时间调问题的延伸,当一个箱子没有容积限制,那么就是时间调度问题 *在时间调度问题中:存在两个可以讨论的问题.1.平均最短时间 2.总的最短时间 *这两个问题都和装箱问题中问题如此类似. */ /* * 上面是我理解的装箱问题,本来是想说背包问题的 * 背包问题的描述:有N件物品和一个容量为V的背包.第

贪心算法(背包问题)

包可以承受15kg重量,有五个物体质量依次为12, 2 ,1, 4, 1价格为4,2,2,10,1,求包所能装的最大价值是 问题分析: 1.先求出价值=格/重量,并用数组保存; 2.根据价值,对数组内元素进行从大到小排序 3.从价值高的开始装,此时,背包问题分为可切割背包问题和不可切割背包问题 //可切割背包问题 #include <iostream> using namespace std; class a { public: int p,w; double v; }; int main()

高级算法——贪心算法(背包问题)

贪心算法不能用来解决离散物品问题的原因是我们无法将“ 半台电视” 放入背包. 规则是按照物品价值高低顺序放入背包. function ksack(values, weights, capacity) { var load = 0; var i = 0; var v = 0; while (load < capacity && i < weights.length) { if (weights[i] <= (capacity - load)) { v += values[i

【贪心算法】背包问题

题目:有一个背包,背包容量是M=150.有7个物品,物品可以分割成任意大小. 要求尽可能让装入背包中的物品总价值最大,但不能超过总容量. 物品 A  B  C  D  E  F  G 重量 35  30  60  50  40  10  25 价值 10  40  30  50  35  40  30 思路: 让你把物品一个个的往包里装,要求装入包中的物品总价值最大,要让总价值最大,就可以想到怎么放一个个的物品才能让总的价值最大,因此可以想到如下三种选择物品的方法,即可能的局部最优解: ①:每次

贪心算法----解背包问题

伪代码: void Knapsack(int n,float M,float v[],float w[],float x[]) { Sort(n,v,w); int i; for (i = 1 ; i <= n ; i++) x[i] = 0; float c=M; for (i=1;i<=n;i++) { if (w[i] > c) break; x[i]=1; c-=w[i]; } if (i <= n) x[i]=c / w[i]; }

部分背包问题的贪心算法正确性证明

一,部分背包问题介绍 首先介绍下0-1背包问题.假设一共有N件物品,第 i 件物品的价值为 Vi ,重量为Wi,一个小偷有一个最多只能装下重量为W的背包,他希望带走的物品越有价值越好,请问:他应该选择哪些物品? 0-1背包问题的特点是:对于某件(更适合的说法是:某类)物品,要么被带走(选择了它),要么不被带走(没有选择它),不存在只带走一部分的情况. 而部分背包问题则是:可以带走一部分.即,部分背包问题可带走的物品 是可以 无限细分的.(连续与离散的区别) 可以把0-1背包问题中的物品想象的一个

贪心算法概述

贪心,顾名思义,就是在把一个大问题分割成无数个相类似的子结构之后,对于每一个子结构,只在乎当前,贪心考虑最优选择,无需考虑整体最优.用专业一点的术语来说,就是无后效性. 具体来说,面对一个大问题,截取当前的一小部分,在这个小部分中选择最优最好的结果.然后以一种迭代,也就是递推的方式选取相似的下一小部分.每次面对一小部分问题,保存最好的结果,丢进集合中.最后在考虑整体的时候,贪心的结果就是集合里这些每个小部分问题保存下来的结果的综合. 贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择.也

野生前端的数据结构练习(12)贪心算法

参考代码可见:https://github.com/dashnowords/blogs/tree/master/Structure/GreedyAlogrithm 一.贪心算法 贪心算法属于比较简单的算法,它总是会选择当下最优解,而不去考虑单次递归时是否会对未来造成影响,也就是说不考虑得到的解是否是全局最优.在很多实际问题中,寻找全局最优解的代价是非常大的,这时候就可以通过求次优解来解决问题,这种思想其实在软件工程中很常见,例如React中著名的DOM Diff算法中需要对比两棵DOM树,树的完

[C++] 贪心算法之活动安排、背包问题

一.贪心算法的基本思想 在求解过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解. 从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解.如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一. 二.贪心算法的基本要素 (1)最优子结构性质 (2)贪心选择性质(局部最优选择) 三.贪心算法实例 1.活动安排 设有n个活