算法學習(三)貪婪算法


下面文章轉自http://182190145.blog.163.com/blog/static/664424420089118405610/

1.貪婪算法引述  

 

先舉個實例來通俗地說明貪婪算法。一個小孩買了價值33美分的糖,並將1美元的錢交給售貨員。售貨員希望用數目最少的硬幣找給小孩。假設提供了數目不限的面值為2 5美分、1 0美分、5美分、及1美分的硬幣。售貨員分步驟組成要找的零錢數,每次加入一個硬幣。

選擇硬幣時所采用的貪婪准則如下:每一次選擇應使零錢數盡量增大。為保證解法的可行性(即:所給的零錢等於要找的零錢數),所選擇的硬幣不應使零錢總數超過最終所需的數目。

現在需要找給小孩6 7美分,首先入選的是兩枚2 5美分的硬幣,第三枚入選的不能是2 5美分的硬幣,否則硬幣的選擇將不可行(零錢總數超過6 7美分),第三枚應選擇1 0美分的硬幣,然后是5美分的,最后加入兩個1美分的硬幣。

   

貪婪算法有種直覺的傾向,在找零錢時,直覺告訴我們應使找出的硬幣數目最少(至少是接近最少的數目)。可以證明采用上述貪婪算法找零錢時所用的硬幣數目的確最少。

可見貪婪算法的實現思路:在每一步中,它要求“貪婪”地選擇最佳操作,並希望通過一系列局部的最優選擇,能夠產生一個整個問題的(全局)最優解。

 

2.貪婪算法原理

 

在傳統貪婪算法中采用逐步構造最優解的方法。在每個階段,都做出一個看上去最優的決策(在一定的標准下)。決策一旦做出,就不可再更改。做出貪婪決策的依據稱為貪婪准則greedy criterion

貪心思想的本質是每次都形成局部最優解,換一種方法說,就是每次都處理出一個最好的方案。即,貪婪法建議通過一系列步驟來構造問題的解,每一步對目前構造的部分解做一個擴展,直到獲得問題的完全解為止。這個技術的核心是,所做的每一步選擇都必須滿足:

l      可行的:即它必須滿足問題的約束。

l      局部最優:它是當前步驟中所有可行選擇中最佳的局部選擇。

l      不可取消:即選擇一旦做出,在算法的后面步驟中就無法改變了。

貪心算法的最大特點就是快。通常,二次方級的存儲要浪費額外的空間,而且很不幸,那些空間經常得不出正解。但是,當使用貪心算法時,這些空間可以幫助算法更容易實現且更快執行。

 

3.貪婪算法實現的難點

 

a. 如何貪婪:

怎樣才能從眾多可行解中找到最優解呢?其實,大部分都是有規律的。在樣例中,貪婪就有很明顯的規律。在每一步中,它要求“貪婪”地選擇最佳操作,並希望通過一系列局部的最優選擇,能夠產生一個整個問題的(全局)最優解。正因為貪心有如此性質,它才能比其他算法要快。然而,還有一些問題並不是這種情況,對於這樣的問題,如果我們關心的是,或者說我們能夠滿足於一個近似解,貪婪算法仍然是有價值的。

 

b. 貪婪的正確性:

要證明所設計貪婪方法的正確性,才是真正挑戰,因為並不是每次局部最優解都會與整體最優解之間有聯系,往往靠貪婪方法生成的解不是最優解。這樣,貪婪方法的證明就成了貪婪正確的關鍵。一個你想出的貪婪方法也許是錯的,即使它在大部分數據中都是可行的,你必須考慮到所有可能出現的特殊情況,並證明你的貪婪方法在這些特殊情況中仍然正確。這樣經過千錘百煉的性質才能構成一個正確的貪婪方法

 

    4.貪婪算法應用范圍

 

貪 婪算法總是做出在當前看來最好的選擇。也就是說貪婪算法並不從整體最優考慮,它所做出的選擇只是在某種意義上的局部最優選擇。當然,希望貪婪算法得到的最 終結果也是整體最優的。雖然貪婪算法不能對所有問題都得到整體最優解,但對許多問題它能產生整體最優解。在一些情況下,即使貪婪算法不能得到整體最優解, 其最終結果卻是最優解的很好近似。

如 果需要解決的問題有貪婪性質存在,那么采用貪婪算法無疑是最好的選擇!因為基於貪婪算法的程序執行起來速度極快,並且節約空間。衡量算法的關鍵就是效率, 即程序執行時消耗的時間和空間。當然,貪心算法有一定使用范圍,而且有一部分極難證明,若是沒有把握,最好還是不要冒險,因為還有其他算法會比它要保險

 

自我編程學習

題目:人民幣有100,50,20,10,5,2,1,0.5,0.2,0.1,在找零時有多種方案,我們選取先取最大的面額的找取

如找零68.9 就為 50+10+5+2+1+0.5+0.2+0.2,利用C#編出這道算法。

 

class Program
    {
        static void Main(string[] args)
        {
            Console.Write("請輸入需要找零的錢:");
            double fMoney = Convert.ToDouble(Console.ReadLine());
            double IMoney = fMoney * 10;
            Console.Write("找零:");
            while (IMoney != 0)
            {
                Console.Write(GetMax(ref IMoney) / 10 + "");
            }
            Console.ReadKey();


        }

        private static double GetMax(ref double IMoney)
        {
            double[] MoneyCount = { 500, 200, 100, 50, 20, 10, 5, 2, 1 };
            double rtn = 0;
            for (int i = 0; i < MoneyCount.Length; i++)
            {
                if (MoneyCount[i] <= IMoney)
                {
                    IMoney -= MoneyCount[i];
                    rtn= MoneyCount[i];
                    break;
                }
            }
            return rtn;
        }

    }

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM