贪心算法简介 -- 活动时间问题

贪心算法简介:
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。

贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。


基本思路
思想
贪心算法的基本思路是从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止 。

过程

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

算法特性编辑
贪婪算法可解决的问题通常大部分都有如下的特性:
随着算法的进行,将积累起其它两个集合:一个包含已经被考虑过并被选出的候选对象,另一个包含已经被考虑过但被丢弃的候选对象。

有一个函数来检查一个候选对象的集合是否提供了问题的解答。该函数不考虑此时的解决方法是否最优。
还有一个函数检查是否一个候选对象的集合是可行的,也即是否可能往该集合上添加更多的候选对象以获得一个解。和上一个函数一样,此时不考虑解决方法的最优性。
选择函数可以指出哪一个剩余的候选对象最有希望构成问题的解。

最后,目标函数给出解的值。

为了解决问题,需要寻找一个构成解的候选对象集合,它可以优化目标函数,贪婪算法一步一步的进行。起初,算法选出的候选对象的集合为空。接下来的每一步中,根据选择函数,算法从剩余候选对象中选出最有希望构成解的对象。如果集合中加上该对象后不可行,那么该对象就被丢弃并不再考虑;否则就加到集合里。每一次都扩充集合,并检查该集合是否构成解。如果贪婪算法正确工作,那么找到的第一个解通常是最优的



举个栗子:
还是上篇文中的 活动时间问题:

想要使用贪心算法的话,得先找到适合贪心算法的规律(局部最优选择)
对于任何非空的活动集合S,假如am是S中结束时间最早的活动,则am一定在S的某个最大兼容活动子集中。

代码实现:

using System;

namespace _5_1_1贪心算法_活动选择问题
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> resultList =  Activity(1, 11, 0, 24);
            foreach (int item in resultList)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }


        //活动开始时间s,结束时间f
        static int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12, 24 };
        static int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 24 };

        //参数:开始/结束的活动个数,开始/结束活动的时间
        public static List<int> Activity(int startNumber, int endNumber,int startTime,int endTime )
        {
            if (startNumber > endNumber || startTime >= endTime) return new List<int>();

            //找到活动结束时间最早的活动
            int temp = 0;
            for (int i = startNumber; i <= endNumber; i++)
            {
                if (s[i] >= startTime && f[i] <= endTime)
                {
                    temp = i;
                    break;
                }
            }
            //找剩下的时间中结束时间最早的活动
            List<int> list = Activity(temp + 1, endNumber, f[temp], endTime);
            list.Add(temp);
            return list;
        }
    }
}

迭代法更符合上面贪心算法的文字描述,,,
代码如下:

using System;

namespace _5_1_2贪心算法_活动选择问题_迭代
{
    class Program
    {
        static void Main(string[] args)
        {
            // 活动开始时间s,结束时间f
            int[] s = { 0, 1, 3, 0, 5, 3, 5, 6, 8, 8, 2, 12, 24 };
            int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 24 };

            //开始结束活动的时间
            int startTime = 0;
            int ensTime = 24;

            //存储最大活动个数的列表
            List<int> list = new List<int>();

            //从第一个活动到最后一个活动
            for (int i = 1; i <= 11; i++)
            {
                //判断每个活动是否子活动时间区间内
                if(s[i]>= startTime && f[i]<= ensTime)
                {
                    //在则记录,不在不处理
                    list.Add(i);

                    //若在则只需要从此活动的结束时间继续搜索即可(更新活动时间)
                    startTime = f[i];
                }
            }

            foreach (int item in list)
            {
                Console.WriteLine(item);
            }

            Console.ReadKey();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/czhenya/article/details/78976035