㈠ 背包問題的貪心演算法所需的計算時間為
背包問題的貪心演算法所需的計算時間為0(nlogn)。
貪心演算法的應用:
活動安排問題:
在活動安排問題中,需要在給定的時間內安排一系列活動,使得所有活動都能完成,並且總的耗時最短。貪心演算法可以通過每次選擇結束時間最早的活動來安排,以達到總耗時最短的目的。
最小生成樹問題:
在最小生成樹問題中,需要在給定的圖中找到一個連接所有節點的最小邊權和的樹。貪心演算法可以通過每次選擇權值最小的邊來連接節點,以達到最小邊權和的目的。例如局部最優解能夠導致全局最優解的問題。在實際應用中,需要根據具體問題的特點來選擇合適的演算法。
背包問題:
在背包問題中,需要在給定的背包容量下,選擇一系列物品放入背包,使得總價值最大。貪心演算法可以通過每次選擇價值最大的物品放入背包,以達到總價值最大的目的。貪心演算法並不適用於所有問題,它只能用於滿足特定條件的問題。
㈡ 貪心思想
在學習數據結構的時候,我們已經見過了貪心思想在Prim和Kruskal中的完美應用,貪心思想因為其的簡潔在演算法中經常會被用到,有的時候在生活中,我們也會無意中使用到l貪心演算法。比如在去shopping時,經常需要進行找零錢的過程,我們總是不自覺的先把大的找出來。
那麼什麼是貪心思想?
貪心演算法總是作出在當前看來最好的選擇,也就是說貪心演算法並不從整體最優考慮,它所作出的選擇只是在某種意義上的局部最優選擇。
只有在滿足最優子結構的情況下貪心演算法得到的結果才是最優結果。
比如找錢的問題,我要給你一百,那麼我盡可能每一次給你最多的。
或者比如磁碟的最優存儲問題,所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列局部最優的選擇,即貪心選擇來達到。
Prim和kruskal演算法都是每次選擇最小的邊納入生成樹。
所謂貪心選擇性質是指所求問題的整體最優解可以通過一系列局部最優的選擇,即貪心選擇來達到。這也是貪心問題和動態規劃問題的主要區別。
在n行m列的正整數矩陣中,要求從每一行中選一個數,使得選出的n個數的和最大。
可運用貪心策略,選n次,每一次選相應行中的最大值即可。
但是,在一個n*m的方格陣中,每一格子賦予一個數,規定每次移動時只能向上或向右,現試找出一條路徑,使其從左下角至右上角所經過的權值之和最大。
同樣考慮貪心策略,從左下角向右上角移動,每次移動選擇權值較大的一個方向。
以2*3矩陣為例,採用貪心的策略得到的是1,3,4,6和為14但是實際的最優結果為1,2,100,6和為109.
所以說貪心演算法並不是總是可行,證明當前問題存在貪心選擇性質(全局最優解可以通過局部最優貪心選擇達到)和最優子結構性質(問題的最優解包含了其子問題的最優解)。所以貪心問題如果當前的選擇不會干擾之後的選擇,則不會出現問題。
其他的情況就需要進行證明,證明的最好辦法就是將最小子問題進行一步步的合並,直到最後還原為最後的原問題,若所得到的解是總體最優的則可以使用貪心思想,否則不可以。
比如上面的問題,我們的走一步的最優解為1,3,然後我們判斷一次走兩步的最優解是否任然為1,3這個路徑,答案顯然不是,變為 1,2,100這個路徑,所以顯然不能使用貪心思想。
假設1元、2元、5元、10元、20元、50元、100元的紙幣分別有c0, c1, c2, c3, c4, c5, c6張。現在要用這些錢來支付K元,至少要用多少張紙幣?用貪心演算法的思想,很顯然,每一步盡可能用面值大的紙幣即可。在日常生活中我們自然而然也是這么做的。
有n個需要在同一天使用同一個教室的活動a1,a2,…,an,教室同一時刻只能由一個活動使用。每個活動ai都有一個開始時間si和結束時間fi 。一旦被選擇後,活動ai就占據半開時間區間[si,fi)。如果[si,fi]和[sj,fj]互不重疊,ai和aj兩個活動就可以被安排在這一天。該問題就是要安排這些活動使得盡量多的活動能不沖突的舉行。
部分背包問題, 有n個物體,第i個物體重量為wi,價值為vi,在總重量不超過C的情況下,讓總價值盡可能的高。每個物體都可以只取一部分。
我們可以考慮重量和價值的比值作為單價。
㈢ 貪心演算法及其應用
求解一個問題時有多個步驟,每個步驟都選擇當下最優的那個解,而不用考慮整體的最優解。通常,當我們面對的問題擁有以下特點的時候,就可以考慮使用貪心演算法。
比如,我們舉個例子,倉庫裡面總共有五種豆子,其對應的重量和總價值如下,現在我們有一個可以裝100KG重量的袋子,怎麼裝才能使得袋子中的豆子價值最大?
我們首先看看這個問題是否符合貪心演算法的使用場景?限制值是袋子100KG,期望值是袋子裡面的價值最高。所以是符合的。那麼我們嘗試著應用下貪心演算法的方法,每一個步驟都尋找當下的最優解,怎麼做呢?
把倉庫裡面的每種豆子價值除以重量,得出每種豆子的單價,那麼當下的最優解,肯定是盡可能最多地裝單價最貴的,也就是先把20KG的黃豆都裝上,然後再把30KG的綠豆都裝上,再裝50KG的紅豆,那麼此時正好裝滿袋子,總價值將是270元,這就是通過貪心演算法求解的答案。
貪心演算法的應用在這個問題上的求解是否是最優解需要一個很復雜的數學論證,我們不用那樣,只要心裡舉幾個例子,驗證下是否比它更好即可,如果舉不出例子,那麼就可以認為這就是最優解了。
雖然貪心演算法雖然在大部分實踐場景中都能得到最優解,但是並不能保證一定是最優解。比如在如下的有向帶權圖中尋找從S到T的最短路徑,那麼答案肯定就是S->A->E->T,總代價為1+4+4=9;
然而,實際上的最短路徑是S->B->D->T,總代價為6。
所以,不能所有這類問題都迷信貪心演算法的求解,但其作為一種演算法指導思想,還是很值得學習的。
除了以上袋子裝豆子的問題之外,還有很多應用場景。這種問題能否使用貪心演算法來解決的關鍵是你能否將問題轉換為貪心演算法適用的問題,即找到問題的限制值和期望值。
我們有m個糖果要分給n個孩子,n大於m,註定有的孩子不能分到糖果。其中,每個糖果的大小都不同,分別為S1,S2,S3...,Sm,每個孩子對糖果的需求也是不同的,為N1,N2,N3...,Nn,那麼我們如何分糖果,才能盡可能滿足最多數量孩子的需求?
這個問題中,限制值是糖果的數量m,期望值滿足最多的孩子需求。對於每個孩子,能用小的糖果滿足其需求,就不要用大的,避免浪費。所以我們可以給所有孩子的需求排個序,從需求最小的孩子開始,用剛好能滿足他的糖果來分給他,以此來分完所有的糖果。
我們有1元、5元、10元、20元、50元、100元紙幣各C1、C5、C10、C20、C50、C100張,現在要購買一個價值K元的東西,請問怎麼才能適用最少的紙幣?
這個問題應該不難,限制值是各個紙幣的張數,期望值是適用最少的紙幣。那麼我們就先用面值最大的100元去付錢,當再加一張100元就超過K時,就更換小面額的,直至正好為K元。
對於n個區間[L1,R1],[L2,R2]...[Ln,Rn],我們怎麼從中選出盡可能多的區間,使它們不相交?
我們需要把這個問題轉換為符合貪心演算法特點的問題,假設這么多區間的最左端點是Lmin,最右端點是Rmax,那麼問題就是在[Lmin,Rmax]中,選擇盡可能多的區間往裡面塞,並且保證它們不相交。這里,限制值就是區間[Lmin,Rmax],期望值就是盡可能多的區間。
我們的解決辦法就是每次從區間中選擇那種左端點>=已經覆蓋區間右邊端點的,且該區間右端點盡可能高小的。如此,我們可以讓未覆蓋區間盡可能地大,才能保證可以塞進去盡可能多的區間。
貪心演算法最重要的就是學會如何將要解決的問題抽象成適合貪心演算法特點的模型,找到限制條件和期望值,只要做好這一步,接下來的就比較簡單了。在平時我們不用刻意去記,多多練習類似的問題才是最有效的學習方法。
㈣ 程序員都應該精通的六種演算法,你會了嗎
對於一名優秀的程序員來說,面對一個項目的需求的時候,一定會在腦海里浮現出最適合解決這個問題的方法是什麼,選對了演算法,就會起到事半功倍的效果,反之,則可能會使程序運行效率低下,還容易出bug。因此,熟悉掌握常用的演算法,是對於一個優秀程序員最基本的要求。
那麼,常用的演算法都有哪些呢?一般來講,在我們日常工作中涉及到的演算法,通常分為以下幾個類型:分治、貪心、迭代、枚舉、回溯、動態規劃。下面我們來一一介紹這幾種演算法。
一、分治演算法
分治演算法,顧名思義,是將一個難以直接解決的大問題,分割成一些規模較小的相同問題,以便各個擊破,分而治之。
分治演算法一般分為三個部分:分解問題、解決問題、合並解。
分治演算法適用於那些問題的規模縮小到一定程度就可以解決、並且各子問題之間相互獨立,求出來的解可以合並為該問題的解的情況。
典型例子比如求解一個無序數組中的最大值,即可以採用分治演算法,示例如下:
def pidAndConquer(arr,leftIndex,rightIndex):
if(rightIndex==leftIndex+1 || rightIndex==leftIndex){
return Math.max(arr[leftIndex],arr[rightIndex]);
}
int mid=(leftIndex+rightIndex)/2;
int leftMax=pidAndConquer(arr,leftIndex,mid);
int rightMax=pidAndConquer(arr,mid,rightIndex);
return Math.max(leftMax,rightMax);
二、貪心演算法
貪心演算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,他所做出的僅是在某種意義上的局部最優解。
貪心演算法的基本思路是把問題分成若干個子問題,然後對每個子問題求解,得到子問題的局部最優解,最後再把子問題的最優解合並成原問題的一個解。這里要注意一點就是貪心演算法得到的不一定是全局最優解。這一缺陷導致了貪心演算法的適用范圍較少,更大的用途在於平衡演算法效率和最終結果應用,類似於:反正就走這么多步,肯定給你一個值,至於是不是最優的,那我就管不了了。就好像去菜市場買幾樣菜,可以經過反復比價之後再買,或者是看到有賣的不管三七二十一先買了,總之最終結果是菜能買回來,但搞不好多花了幾塊錢。
典型例子比如部分背包問題:有n個物體,第i個物體的重量為Wi,價值為Vi,在總重量不超過C的情況下讓總價值盡量高。每一個物體可以只取走一部分,價值和重量按比例計算。
貪心策略就是,每次都先拿性價比高的,判斷不超過C。
三、迭代演算法
迭代法也稱輾轉法,是一種不斷用變數的舊值遞推新值的過程。迭代演算法是用計算機解決問題的一種基本方法,它利用計算機運算速度快、適合做重復性操作的特點,讓計算機對一組指令(或一定步驟)進行重復執行,在每次執行這組指令(或這些步驟)時,都從變數的原值推出它的一個新值。最終得到問題的結果。
迭代演算法適用於那些每步輸入參數變數一定,前值可以作為下一步輸入參數的問題。
典型例子比如說,用迭代演算法計算斐波那契數列。
四、枚舉演算法
枚舉演算法是我們在日常中使用到的最多的一個演算法,它的核心思想就是:枚舉所有的可能。枚舉法的本質就是從所有候選答案中去搜索正確地解。
枚舉演算法適用於候選答案數量一定的情況。
典型例子包括雞錢問題,有公雞5,母雞3,三小雞1,求m錢n雞的所有可能解。可以採用一個三重循環將所有情況枚舉出來。代碼如下:
五、回溯演算法
回溯演算法是一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就「回溯」返回,嘗試別的路徑。
許多復雜的,規模較大的問題都可以使用回溯法,有「通用解題方法」的美稱。
典型例子是8皇後演算法。在8 8格的國際象棋上擺放八個皇後,使其不能互相攻擊,即任意兩個皇後都不能處於同一行、同一列或同一斜線上,問一共有多少種擺法。
回溯法是求解皇後問題最經典的方法。演算法的思想在於如果一個皇後選定了位置,那麼下一個皇後的位置便被限制住了,下一個皇後需要一直找直到找到安全位置,如果沒有找到,那麼便要回溯到上一個皇後,那麼上一個皇後的位置就要改變,這樣一直遞歸直到所有的情況都被舉出。
六、動態規劃演算法
動態規劃過程是:每次決策依賴於當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,所以,這種多階段最優化決策解決問題的過程就稱為動態規劃。
動態規劃演算法適用於當某階段狀態給定以後,在這階段以後的過程的發展不受這段以前各段狀態的影響,即無後效性的問題。
典型例子比如說背包問題,給定背包容量及物品重量和價值,要求背包裝的物品價值最大。
㈤ 演算法怎麼學
貪心演算法的定義:
貪心演算法是指在對問題求解時,總是做出在當前看來是最好的選擇。也就是說,不從整體最優上加以考慮,只做出在某種意義上的局部最優解。貪心演算法不是對所有問題都能得到整體最優解,關鍵是貪心策略的選擇,選擇的貪心策略必須具備無後效性,即某個狀態以前的過程不會影響以後的狀態,只與當前狀態有關。
解題的一般步驟是:
1.建立數學模型來描述問題;
2.把求解的問題分成若干個子問題;
3.對每一子問題求解,得到子問題的局部最優解;
4.把子問題的局部最優解合成原來問題的一個解。
如果大家比較了解動態規劃,就會發現它們之間的相似之處。最優解問題大部分都可以拆分成一個個的子問題,把解空間的遍歷視作對子問題樹的遍歷,則以某種形式對樹整個的遍歷一遍就可以求出最優解,大部分情況下這是不可行的。貪心演算法和動態規劃本質上是對子問題樹的一種修剪,兩種演算法要求問題都具有的一個性質就是子問題最優性(組成最優解的每一個子問題的解,對於這個子問題本身肯定也是最優的)。動態規劃方法代表了這一類問題的一般解法,我們自底向上構造子問題的解,對每一個子樹的根,求出下面每一個葉子的值,並且以其中的最優值作為自身的值,其它的值舍棄。而貪心演算法是動態規劃方法的一個特例,可以證明每一個子樹的根的值不取決於下面葉子的值,而只取決於當前問題的狀況。換句話說,不需要知道一個節點所有子樹的情況,就可以求出這個節點的值。由於貪心演算法的這個特性,它對解空間樹的遍歷不需要自底向上,而只需要自根開始,選擇最優的路,一直走到底就可以了。
話不多說,我們來看幾個具體的例子慢慢理解它:
1.活動選擇問題
這是《演算法導論》上的例子,也是一個非常經典的問題。有n個需要在同一天使用同一個教室的活動a1,a2,…,an,教室同一時刻只能由一個活動使用。每個活動ai都有一個開始時間si和結束時間fi 。一旦被選擇後,活動ai就占據半開時間區間[si,fi)。如果[si,fi]和[sj,fj]互不重疊,ai和aj兩個活動就可以被安排在這一天。該問題就是要安排這些活動使得盡量多的活動能不沖突的舉行。例如下圖所示的活動集合S,其中各項活動按照結束時間單調遞增排序。
關於貪心演算法的基礎知識就簡要介紹到這里,希望能作為大家繼續深入學習的基礎。