下面文章轉自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; } }