贪心算法-活动选择问题

《贪心算法-活动选择问题》

《贪心算法-活动选择问题》

a情况 

    比如S12就是i>=j-1,S12表示a1活动结束之后,a2活动开始之前的活动集合,显然这a1,a2之间并没有活动。i比j大就是非正常情况了。

b情况

    存在活动时,c[i,j]=max{c[i,k]+c[k,j]+1}   k就是用来分解成子问题的其中一个活动ak,用于遍历,+1是因为结果需要加上ak自身。

1.动态规划-自底向下

namespace Code5
{
    class Program
    {
        static void Main(string[] args)
        {
            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 };

            List<int>[,] result = new List<int>[13, 13];// 默认值null
            for (int m = 0; m < 13; m++)
            {
                for (int n = 0; n < 13; n++)
                {
                    result[m, n] = new List<int>();//构造result 
                }
            }//默认值就是空list集合

            //两层循环遍历每个区间情况
            for (int j = 0; j < 13; j++)//从j=2开始
            {
                for (int i = 0; i < j - 1; i++)//从i=0开始
                {
                    // S[ij] i结束之后 j开始之前的 活动集合
                    // f[i]  s[j] 这个时间区间内的所有活动
                    List<int> sij = new List<int>();
                    //number 活动编号,最后一个24不算在内所以要-1
                    for (int number = 1; number < s.Length - 1; number++)
                    {
                        //遍历每个活动,判断哪个活动的时间在区间内
                        if (s[number] >= f[i] && f[number] <= s[j])
                        {
                            sij.Add(number);
                        }
                    }

                    if (sij.Count > 0)//区间内有活动可以加入的情况下
                    {
                        //result[i,j]=max{ result[i,k]+result[k,j]+ k }

                        int maxCount = 0;
                        List<int> tempList = new List<int>();//保存最大兼容子集
                        foreach (int k in sij)
                        {
                            int count = result[i, k].Count + result[k, j].Count + 1;
                            if (maxCount < count)
                            {
                                maxCount = count;
                                //Union 获得并集
                                tempList = 
                                   result[i, k].Union<int>(result[k, j]).ToList<int>();
                                tempList.Add(k);
                            }
                        }
                        result[i, j] = tempList;
                    }
                }
            }
            List<int> l = result[0, 12];
            foreach (int temp in l)
            {
                Console.WriteLine(temp);
            }
            Console.ReadKey();
        }
    }
}

2.贪心算法

活动时间是按照结束时间进行排序的。获得第一个最早结束的活动之后,第一个活动的结束时间f[1],下一个活动就是找一个开始时间s[n]<f[1]且结束时间最早的活动。

《贪心算法-活动选择问题》

比如 a[1]的时间是[1,4] 下一个活动只能是从4开始。可以从表中看到a[4],a[6],a[7],a[8],a[9],a[11]都是在4之后开始的。此时找出这些活动中最早结束的,就是第二个被安排的活动。也就是a[5]。同理继续查找就会找到a[8],a[11]。结果与上面动态规划得出的结果相同。

递归解决

namespace Code5
{
    class Program
    {
        static void Main(string[] args)
        {

            List<int> list = ActivitySelection(1, 11, 0, 24);
            foreach (int temp in list)
            {
                Console.WriteLine(temp);
            }
            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 };
        /// <summary>
        /// 活动选择方法
        /// </summary>
        /// <param name="startActivityNumber">开始活动编号</param>
        /// <param name="endActivityNumber">结束活动编号</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <returns></returns>
        public static List<int> ActivitySelection
        (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 = 
            ActivitySelection(tempNumber + 1, endActivityNumber, f[tempNumber], endTime);
            list.Add(tempNumber);//加入这个最早的活动
            return list;
        }
    }
}

迭代解决

namespace Code5
{
    class Program
    {
        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 };

            int startTime = 0;
            int endTime = 24;
            List<int> list = new List<int>();
            for (int number = 1; number <= 11; number++)
            {
                if (s[number] >= startTime && f[number] <= endTime)
                {
                    list.Add(number);
                    startTime = f[number];
                }
            }
            foreach (int i in list)
            {
                Console.WriteLine(i);
            }
            Console.ReadKey();
        }
    }

}

 

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/qq_36718838/article/details/82179147
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞