【算法】-贪心算法初识

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiqibei666/article/details/82959020

前言:

  了解一个事物的开始,我们必然要关切是什么?为什么?怎么用的问题,算法的学习开始也不例外;

正文:

1、基本概念

  1.1、问题求解时总是做出当前看来最好的选择,而不从整体加以考虑,也就是所做出的选择是当前局部最优选择,不一定是整体最优解;

  1.2、理解:

  • 不追求最优解,只求可行解,通俗讲不求最好,只求可好;
  • 每一次都按照贪婪准则找一个解,故到n步后(n为问题规模)得到问题的所有解,如果找不到所有解,则修改贪婪准则,放宽贪婪条件或修改算法某些细节,重新从头开始找解;
  • 每一步所找到的解是这一步中的最优解,(按照贪婪准则来说),但每步最优解所形成的的整体解并不一定最优;
  • 个人理解:贪心是有条件的,根据我的贪心策略选择,具有一定的时效性;一般根据选择的性质,往往贪心算法会做一个排序;

2、二要素

  • 贪心选择

  贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到,与动态规划的主要区别;
  贪心选择是采用从顶向下、以迭代的方法做出相继选择,每做一次贪心选择就将所求问题简化为一个规模更小的子问题;
  通过每一步贪心选择,最终可得到子问题的组合作为一个整体最优解;

  • 最优子结构

  当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质
  贪心算法的每一次操作都对结果产生直接影响,而动态规划则不是,贪心算法对每个子问题的解决方案都做出选择,不能回退;

在这里插入图片描述

3、基本思路

  • 建立数学模型来描述问题。
  • 把求解的问题分成若干个子问题。把求解的问题分成若干个子问题。
  • 对每一子问题求解,得到子问题的局部最优解。对每一子问题求解,得到子问题的局部最优解。
  • 把子问题的解局部最优解合成原来解问题的一个解。把子问题的解局部最优解合成原来解问题的一个解。

实现该算法的过程:

  • 从问题的某一初始解出发;
  • while 能朝给定总目标前进一步 do
  • 求出可行解的一个解元素;
  • 由所有解元素组合成问题的一个可行解

4、常用应用体现

  • Kruskal、 Prim、 Dijkstra等体现“贪心”思想的图形算法
  • 广泛地应用于树与图的处理;
  • 背包,找零钱,活动安排;

5、例题分析:–以活动安排为例

  • 首先对各个活动按照活动完成时间递增进行排序;
  • 依据贪心法则:有限时间内在房间内安排活动
    在这里插入图片描述
  • 代码实现:
  • 迭代实现
static void Main(string[] args)
        {
            //定义数组:活动开始时间,完成时间
            int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
            int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};

            //房间可允许活动开始时间为0,结束时间为24;
            int startTime = 0;
            int endTime = 24;

            //实例化
            List<int> list = new List<int>();

            //for循环判断查找符合贪心法则的局部最优解
            //number=1,从第一个活动开始,11为活动总数n;
            for (int number = 1; number <= 11; number++)
            {
                //活动开始时间>房间可用开始时间,活动开始时间应不早于房间可使用时间
                //且活动完成时间不晚于房间最晚可用时间24小时;
                if (s[number] >= startTime && f[number] <= endTime)
                {
                    //将查找到的活动序号放入集合中
                    list.Add(number);
                    //下一个活动最早开始时间为此活动结束时间
                    startTime = f[number];
                }
            }

            //遍历集合元素,显示
            foreach (int i in list)
            {
                Console.WriteLine(i);
            }
            Console.ReadKey();
        }
  • 递归实现
static void Main(string[] args)
        {
            //定义一个集合,存放,startnumber=1,总的活动为11,
            //活动开始时间0 -24,最长使用时间24小时;
            List<int> list = ActivitySelect(1, 11, 0, 24);

            //遍历集合元素
            foreach (int i in list)
            {
                Console.WriteLine(i);
            }
            Console.ReadKey();
        }

        //定义数组 活动开始时间,完成时间
        static int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12 };
        static int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };


        public static List<int> ActivitySelect(int startActivityNumber, int endActivityNumber, int startTime, int endTime)
        {
            if (startActivityNumber > endActivityNumber || startTime >= endTime)
            {
                return new List<int>();
            }
            //找到结束时间最早的活动 
            int tempNumber = 0;//未选中的活动
            for (int number = startActivityNumber; number <= endActivityNumber; number++)
            {
                if (s[number] >= startTime && f[number] <= endTime)
                {
                    tempNumber = number;
                    break;
                }
            }
            List<int> list = ActivitySelect(tempNumber + 1, endActivityNumber, f[tempNumber], endTime);
            list.Add(tempNumber);
            return list;
        }

小结:

  对贪心算法有个基础的认识,接下来软考做题学习以及之后的学习过程中还需要更深入的进行探索和学习;

将分享的内容总结在博客中,有哪些没有说明白或理解有偏差的,一起交流学习;

猜你喜欢

转载自blog.csdn.net/qiqibei666/article/details/82959020
今日推荐