wangjun的博客

主要作为笔记,也分享互相学习

贪心算法

1. 贪心算法

        对于许多最优化问题,使用动态规划算法来求最优解有些杀鸡用牛刀了,可以使用更加简单、更加高效的算法。贪心算法就是这样的算法,它在每一步做出当时看起来最佳的选择。也就是说它总是做出局部最优的选择,从而得到全局最优解。

        对于某些问题并不保证得到最0优解,但对很多问题确实可以求得最优解。

2.活动选择问题

        有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。该问题就是要安排这些活动使得尽量多的活动能不冲突的举行(最大兼容活动子集)。例如下图所示的活动集合S,其中各项活动按照结束时间单调递增排序。

        {a3,a9,a11}是一个兼容的活动子集,但它不是最大子集,因为子集{a1,a4,a8,a11}更大,实际上它是我们这个问题的最大兼容子集,但它不是唯一的一个{a2a4a9a11}

2.1动态规划算法解决思路

      我们使用Sij代表在活动ai结束之后,且在aj开始之前的那些活动的集合,我们使用c[i,j]代表Sij的最大兼容活动子集的大小,对于上述问题就是求c[0,12]的解
  a, i>=j-1或者Sij中没有任何活动元素的时候, c[i,j]=0
  b,当i<j-1
  1Sij不存在活动,c[i,j]=0
  2Sij存在活动的时候,c[i,j]=max{c[i,k]+c[k,j]+1}  ak属于Sij,这里是遍历Sij的集合,然后求得最大兼容子集

2.2贪心算法

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

  递归解决

  迭代解决

3.代码实现

3.1 活动选择问题_动态规划_自底向上

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

namespace _513_活动选择问题_动态规划_自底向上
{
    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];
            for(int m=0;m<13;m++)
            {
                for(int n=0;n<13;n++)
                {
                    result[m, n] = new List<int>();
                }
            }


            for(int j=0;j<13;j++)
            {
                for(int i=0;i<j-1;i++)
                {
                    //s[i,j],代表i结束之后,j开始之前的活动集合
                    //f[i]  s[j]这个时间区间内的所有活动
                    List<int> sij = new List<int>();
                    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 number in sij)
                        {
                            int count = result[i, number].Count + result[number, j].Count+1;
                            if(maxCount<count)
                            {
                                maxCount = count;
                                tempList = result[i, number].Union<int>(result[number, j]).ToList<int>();
                                tempList.Add(number);
                            }
                        }
                        result[i, j] = tempList;
                    }
                }
            }
            List<int> l = result[0, 12];
            foreach(int temp in l)
            {
                Console.WriteLine(temp);
            }
            Console.ReadKey();
        }
    }
}

3.2 活动选择问题_贪心算法_递归解决

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

namespace _514_活动选择问题_贪心算法_递归解决
{
    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, 24 };
        static int[] f = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 24 };


        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;
        }
    }
}

3.3 活动选择问题_贪心算法_迭代解决

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

namespace _515_活动选择问题_贪心算法_迭代解决
{
    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 };

            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 temp in list)
            {
                Console.WriteLine(temp);
            }
            Console.ReadKey();
        }
    }
}

4. 钱币找零

        这个问题在我们的日常生活中就更加普遍了。假设1元、2元、5元、10元、20元、50元、100元的纸币分别有c0,c1, c2, c3, c4, c5, c6张。现在要用这些钱来支付K元,至少要用多少张纸币?用贪心算法的思想,很显然,每一步尽可能用面值大的纸币即可。
intCount[N]={3,0,2,1,0,3,5}; 

intValue[N]={1,2,5,10,20,50,100};  

4.1 钱币找零_贪心算法

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

namespace _516_钱币找零_贪心算法
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] count = { 3, 0, 2, 1, 0, 3, 5 };//每种面额钱币的张数
            int[] amount = { 1, 2, 5, 10, 20, 50, 100 };//拥有的钱币面额

            int[] result = Change(320, count, amount);

            foreach(int temp in result)
            {
                Console.Write(temp+" ");

            }
            Console.ReadKey();
        }
        /// <summary>
        /// 钱币找零
        /// </summary>
        /// <param name="k">需要找零的总金额</param>
        /// <param name="count"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        public static int[] Change(int k,int[] count,int[] amount)
        {
            int index = amount.Length - 1;//得到最大面值的钱币索引
            int[] result = new int[count.Length + 1];//保存每种面额的钱换出了多少张,最后一位保存为换的金额
            while(true)
            {
                if (index == -1 || k <= 0) break;//当index==-1(所有的钱都被换完了)或者已经将k换完了,循环结束
                if (k > count[index]*amount[index])//将所有的100拿出来都不够换时
                {
                    result[index] = count[index];
                    k -= count[index] * amount[index];
                }
                else
                {
                    result[index]= k / amount[index];
                    k -= result[index] * amount[index];
                }

                index--;
            }
            result[amount.Length] = k;
            return result;
        }
    }
}

阅读更多
想对作者说点什么? 我来说一句

算法课ppt,贪心算法

2011年05月27日 887KB 下载

贪心算法贪心算法贪心算法

2011年07月13日 50KB 下载

贪心算法,JAVA语言

2010年12月12日 23KB 下载

动态规划算法与贪心算法

2009年09月13日 59KB 下载

贪心算法 贪心 算法 贪心的算法

2010年08月27日 247KB 下载

贪心算法的数学原理(pdf)

2010年06月24日 298KB 下载

贪心算法的应用

2011年09月30日 83KB 下载

没有更多推荐了,返回首页

不良信息举报

贪心算法

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭