1. 程式人生 > >李麗貝 廊坊師範學院資訊科技提高班十四期

李麗貝 廊坊師範學院資訊科技提高班十四期

前言:

  瞭解一個事物的開始,我們必然要關切是什麼?為什麼?怎麼用的問題,演算法的學習開始也不例外;

正文:

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

小結:

  對貪心演算法有個基礎的認識,接下來軟考做題學習以及之後的學習過程中還需要更深入的進行探索和學習;

將分享的內容總結在部落格中,有哪些沒有說明白或理解有偏差的,一起交流學習;