• 贪心算法之背包问题


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

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

    具体算法描述:

    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();
            }
        }
    }
  • 相关阅读:
    [Ansible]copy 模块
    [Ansible]script模块
    [Ansible]command shell模块
    [Ansible]Systemd 模块
    [Ansible]YUM 模块
    [Ansible]yum_repository模块 添加 删除yum源
    [Ceph]osd 无法启动 start request repeated too quickly for ceph-osd@1.service
    [Ceph]pool 删除 Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool
    题解 烷基计数 加强版 加强版
    Polya 定理 学习笔记
  • 原文地址:https://www.cnblogs.com/lihonglin2016/p/4299016.html
Copyright © 2020-2023  润新知