1. 程式人生 > >分治法,動態規劃及貪心演算法區別

分治法,動態規劃及貪心演算法區別

轉自:http://hxrs.iteye.com/blog/1055478

分治法,動態規劃法,貪心演算法這三者之間有類似之處,比如都需要將問題劃分為一個個子問題,然後通過解決這些子問題來解決最終問題。但其實這三者之間的區別還是蠻大的。

1.分治法

    分治法(divide-and-conquer):將原問題劃分成n個規模較小而結構與原問題相似的子問題;遞迴地解決這些子問題,然後再合併其結果,就得到原問題的解。

   分治模式在每一層遞迴上都有三個步驟:

  • 分解(Divide):將原問題分解成一系列子問題;
  • 解決(conquer):遞迴地解各個子問題。若子問題足夠小,則直接求解;
  • 合併(Combine):將子問題的結果合併成原問題的解。

   合併排序(merge sort)是一個典型分治法的例子。其對應的直觀的操作如下:

  • 分解:將n個元素分成各含n/2個元素的子序列;
  • 解決:用合併排序法對兩個子序列遞迴地排序;
  • 合併:合併兩個已排序的子序列以得到排序結果。

2. 動態規劃法

   動態規劃演算法的設計可以分為如下4個步驟:

  • 描述最優解的結構
  • 遞迴定義最優解的值
  • 按自底向上的方式計算最優解的值
  • 由計算出的結果構造一個最優解

     分治法是指將問題劃分成一些獨立地子問題,遞迴地求解各子問題,然後合併子問題的解而得到原問題的解。與此不同,動態規劃適用於子問題獨立且重疊的情況,也就是各子問題包含公共的子子問題。在這種情況下,若用分治法則會做許多不必要的工作,即重複地求解公共的子問題。動態規劃演算法對每個子子問題只求解一次,將其結果儲存在一張表中,從而避免每次遇到各個子問題時重新計算答案。

   適合採用動態規劃方法的最優化問題中的兩個要素:最優子結構和重疊子問題。 

   最優子結構:如果問題的一個最優解中包含了子問題的最優解,則該問題具有最優子結構。

       重疊子問題:適用於動態規劃求解的最優化問題必須具有的第二個要素是子問題的空間要很小,也就是用來求解原問題的遞迴演算法課反覆地解同樣的子問題,而不是總在產生新的子問題。對兩個子問題來說,如果它們確實是相同的子問題,只是作為不同問題的子問題出現的話,則它們是重疊的。

    “分治法:各子問題獨立   動態規劃:各子問題重疊”

     演算法導論: 動態規劃要求其子問題既要獨立又要重疊,這看上去似乎有些奇怪。雖然這兩點要求聽起來可能矛盾的,但它們描述了兩種不同的概念,而不是同一個問題的兩個方面。如果同一個問題的兩個子問題不共享資源,則它們就是獨立的。對兩個子問題倆說,如果它們確實是相同的子問題,只是作為不同問題的子問題出現的話,是重疊的,則它們是重疊的。

3. 貪心演算法

    對許多最優化問題來說,採用動態規劃方法來決定最佳選擇有點“殺雞用牛刀”了,只要採用另一些更簡單有效的演算法就行了。貪心演算法是使所做的選擇看起來都是當前最佳的,期望通過所做的區域性最優選擇來產生出一個全域性最優解。貪心演算法對大多數優化問題來說能產生最優解,但也不一定總是這樣的。

    貪心演算法只需考慮一個選擇(亦即,貪心的選擇);在做貪心選擇時,子問題之一必須是空的,因此只留下一個非空子問題。

    貪心演算法與動態規劃與很多相似之處。特別地,貪心演算法適用的問題也是最優子結構。貪心演算法與動態規劃有一個顯著的區別,就是貪心演算法中,是以自頂向下的方式使用最優子結構的。貪心演算法會先做選擇,在當時看起來是最優的選擇,然後再求解一個結果子問題,而不是先尋找子問題的最優解,然後再做選擇。

        貪心演算法是通過做一系列的選擇來給出某一問題的最優解。對演算法中的每一個決策點,做一個當時看起來是最佳的選擇。這一點是貪心演算法不同於動態規劃之處。在動態規劃中,每一步都要做出選擇,但是這些選擇依賴於子問題的解。因此,解動態規劃問題一般是自底向上,從小子問題處理至大子問題。貪心演算法所做的當前選擇可能要依賴於已經做出的所有選擇,但不依賴於有待於做出的選擇或子問題的解。因此,貪心演算法通常是自頂向下地做出貪心選擇,不斷地將給定的問題例項歸約為更小的問題。貪心演算法劃分子問題的結果,通常是僅存在一個非空的子問題。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

轉自:http://blog.csdn.NET/penzo/article/details/6001314

區別:
動態規劃
全域性最優解中一定包含某個區域性最優解,但不一定包含前一個區域性最優解,因此需要記錄之前的所有最優解。
條件:最優子結構;重疊子問題。
方法:自底向上構造子問題的解。
例子:子序列最大和問題,滑雪問題

貪心演算法
條件:每一步的最優解一定依賴上一步的最優解。
方法:從問題的某一個初始解出發逐步逼近給定的目標,以儘可能快的地求得更好的解。當達到某演算法中的某一步不能再繼續前進時,演算法停止。
存在問題:
(1)不能保證求得的最後解是最佳的;
(2)不能用來求最大最小解的問題;比如錢幣分為1元3元4元,要拿6元錢,貪心的話,先拿4,再拿兩個1,一共3張錢;實際最優卻是兩張3元就夠了。
“貪心”特性:它對解空間樹的遍歷不需要自底向上,而只需要自根開始,選擇最優的路,一直走到底就可以了。這樣,與動態規劃相比,它的代價只取決於子問題的數目,而選擇數目總為1。
例子:哈夫曼樹,錢幣組合,設定雷達問題
========================
聯絡:
(1)都是一種遞推演算法;
(2)貪心和動態規劃本質上是對子問題樹的一種修剪。兩種演算法要求問題都具有的一個性質就是“子問題最優性”。即組成最優解的每一個子問題的解,對於這個子問題本身肯定也是最優的。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

轉自:http://blog.csdn.Net/intrepyd/article/details/4374856

寫在前面

1.          本文內容對應《演算法導論》(第2版)》第15章。

2.          主要介紹了動態規劃演算法的基本概念、適用問題,以及求解步驟。最後,簡單地比較分析了貪心演算法的基本思想。

3.          希望本文對您有所幫助,也歡迎您給我提意見和建議。

動態規劃

基本概念

分治法一樣,動態規劃(dynamic programming)是通過組合子問題的解而解決整個問題的。分治法是指將問題劃分成一些獨立地子問題,遞迴地求解各子問題,然後合併子問題的解而得到原問題的解。與此不同,動態規劃適用於子問題不是獨立的情況,也就是各子問題包含公共的子子問題。在這種情況下,若用分治法則會做許多不必要的工作,即重複地求解公共的子問題。動態規劃演算法對每個子子問題只求解一次,將其結果儲存在一張表中,從而避免每次遇到各個子問題時重新計算答案。

動態規劃適用問題

動態規劃通常應用於最優化問題,即要做出一組選擇以達到一個最優解。適合動態規劃方法的最優化問題必須具備兩個要素:最優子結構和重疊子問題。

²         最優子結構

用動態規劃求解優化問題的第一步是描述最優解的結構。如果問題的一個最優解中包含了子問題的最優解,則該問題具有最優子結構。通常,可以利用自頂向下的思想來尋找最優子結構,即縮小原問題的規模,判斷子問題的最優解是否是組成原問題最優解的一部分。

         可以用無權最短路徑和無權最長簡單路徑的例子,體會最優子結構的含義。假設p是從u到v的無權最短路徑,那麼p必定包含一箇中間頂點w(可能是u或v)。如果p1、p2分別是u到w和w到v的無權最短路徑,可以肯定,p將由p1和p2構成。因此,無權最短路徑問題具有最優子結構。相反,假設p是u到v的無權最長簡單路徑,p1和p2分別是u到w和w到v的無權最長簡單路徑。因為p1路徑中可以包含頂點v,而p2必定包含頂點v,所以當p1和p2合併時將形成環路,從而不能構成原問題的最優解p。用另一種方式看,在求解一個子問題時,對資源的使用(如這裡的頂點)使得它們無法被另一個子問題所用。因此,無權最長簡單路徑問題不具有最優子結構,不能利用動態規劃求解。

²         重疊子問題

適用於動態規劃求解的最優化問題必須具有的第二個要素是子問題的空間要很小,也就是用來求解原問題的遞迴演算法課反覆地解同樣的子問題,而不是總在產生新的子問題。對兩個子問題來說,如果它們確實是相同的子問題,只是作為不同問題的子問題出現的話,則它們是重疊的。仍然以無權最短路徑為例,兩個相鄰頂點間的無權最短路徑,可以是包含這兩個頂點的任意三個頂點的無權最短路徑問題的重疊子問題。

動態規劃求解步驟

動態規劃演算法的設計可以分為如下四個步驟:

1)   描述最優解的結構。通過對最優解結構的分析,判斷如何對原問題進行最優子結構劃分。

2)   利用子問題的最優解來遞迴定義一個最優解的值,這時遞迴求解的重要依據。

3)   按自底向上的方式計算最優解的值。下層子問題的最優解通常被記錄在表格中,供上層求解時查詢。

4)   由計算出的結果構造一個最優解。實際應用中,為了描述如何得到這個最優解,通常在自底向上的求解過程中,把每一個子問題中所作的選擇儲存在一個表格中。

最長公共子序列

以最長公共子序列為例,體會動態規劃的求解過程。給定一個序列X=<x1, x2, …, xm>,另一個序列Z=<z1, z2, …, zk>是X的一個子序列,如果存在X的一個嚴格遞增下標序列<i1, i2, …, ik>,使得對所有的j=1, 2, …, k,有xij=zj。在最長公共子序列(LCS,longest common subsequence)問題中, 給定了兩個序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>,希望找出X和Y的最大長度公共子序列Z=<z1, z2, …, zk>。

1)     描述最優解的結構。嘗試縮小原問題的規模,尋找最優子結構。這裡,如果xm= yn,那麼zk =xm= yn且Zk-1是Xm-1和Yn-1的LCS;如果xm≠yn,那麼zk≠xm蘊含Z是Xm-1和Y的一個LCS;如果xm≠yn,那麼zk≠yn蘊含Z是Xm和Yn-1的一個LCS。

2)     利用上面的最優子結構,定義最優解的遞迴式。如果i=0,或j=0,那麼c[i, j]=0;如果i, j>0且xi=yi,那麼c[i, j]=c[i-1, j-1]+1;如果i, j>0且xi≠yi,那麼c[i, j]=max(c[i, j-1], c[i-1, j])。這裡,c[i, j]為序列Xi和Yi的一個LCS的長度。

3)     自底向上地計算LCS的長度,同時,記錄LCS的元素。

4)     根據上一步的結果,直接得到LCS及其長度。

/*

 * x_array,x_length: X序列及其長度

 * y_array,y_length: Y序列及其長度

 * b_array,b_length: 記錄LCS的元素,b_length=min(x_length,y_length)

 * 返回LCS長度

 */

int dynamic_lcs(int *x_array, int x_length,

                   int *y_array, int y_length,

                   int *b_array, int b_length)

{

    int i, j, k, lcs_length;

    int **c_array=NULL;

    c_array = malloc(sizeof(int *)*(x_length+1));

    for(i=0; i<x_length+1; i++)

                  c_array[i] = malloc(sizeof(int)*(y_length+1));

    for(i=0; i<x_length+1; i++)

                  c_array[i][0] = 0;

    for(j=0; j<y_length+1; j++)

                  c_array[0][j] = 0;

    k = 0;

    for(i=0; i<x_length; i++)

    {

                  for(j=0; j<y_length; j++)

                  {

                        if(x_array[i] == y_array[j])

                        {

                                      c_array[i+1][j+1] = c_array[i][j]+1;

                                      b_array[k++] = x_array[i];

                        }

                        else if(c_array[i+1][j] >= c_array[i][j+1])

                                      c_array[i+1][j+1] = c_array[i+1][j];

                        else

                                      c_array[i+1][j+1] = c_array[i][j+1];

                  }

    }

    lcs_length = c_array[x_length][y_length];

    for(i=0; i<x_length+1; i++)

                  free(c_array[i]);

    free(c_array);

    return lcs_length;  

}

貪心演算法基本思想

貪心演算法是通過做一系列的選擇來給出某一問題的最優解。對演算法中的每一個決策點,做一個當時看起來是最佳的選擇。這一點是貪心演算法不同於動態規劃之處。在動態規劃中,每一步都要做出選擇,但是這些選擇依賴於子問題的解。因此,解動態規劃問題一般是自底向上,從小子問題處理至大子問題。貪心演算法所做的當前選擇可能要依賴於已經做出的所有選擇,但不依賴於有待於做出的選擇或子問題的解。因此,貪心演算法通常是自頂向下地做出貪心選擇,不斷地將給定的問題例項歸約為更小的問題。貪心演算法劃分子問題的結果,通常是僅存在一個非空的子問題。


相關推薦

治法動態規劃貪心演算法區別

轉自:http://hxrs.iteye.com/blog/1055478 分治法,動態規劃法,貪心演算法這三者之間有類似之處,比如都需要將問題劃分為一個個子問題,然後通過解決這些子問題來解決最終問題。但其實這三者之間的區別還是蠻大的。 1.分治法     分治法(di

五大常用演算法——治法動態規劃回溯法分支界限法貪心演算法

分治演算法 一、基本概念    在電腦科學中,分治法是一種很重要的演算法。字面上的解釋是“分而治之”,就是把一個複雜的問題分成兩個或更多的相同或相似的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合併。這個技巧是很多高效

六中常用演算法設計:窮舉法、治法動態規劃貪心法、回溯法和分支限界法

演算法設計之六種常用演算法設計方法 1.直接遍歷態(窮舉法)        程式執行狀態是可以遍歷的,遍歷演算法執行每一個狀態,最終會找到一個最優的可行解;適用於解決極小規模或者複雜度線性增長,而線

圖形結構:遍歷模型治法動態規劃回溯法BFSDFS

圖形結構,是樹形結構的擴充套件。 我們在回溯法裡面瞭解到幾種結構:二叉樹,排列樹,完全n叉樹,這幾種解空間型別,都可以直接使用回溯法的框架解決。 二叉樹,排列樹,完全n叉樹,都可以看成x叉樹的變形,而圖形結構就是x叉樹。 在此之前,我們先明白一點:一顆二叉樹是什麼,他是某一顆二叉

治法動態規劃對比

分治法是將問題劃分成一些獨立的子問題,遞迴地求解各子問題,然後合併子問題的解。 動態規劃適用於子問題不是獨立的情況,也就是各子問題包含公共的子子問題。 原則上,解決動態規劃的方法是自底向上,且要求解出最優子問題和當前問題的關係才能解決更高層次的問題!!!

治法動態規劃法貪心回溯法分支限界法的區別和聯絡以及適用情況

    筆者這學期的《演算法設計與分析》課程已經進入尾聲,在這裡對學過的演算法進行總結歸納。筆者先對各個演算法的思想進行簡單的陳述,然後再進行對比。一、演算法思想    (一)分治法(divide and conquer method)    是將待求解的原問題劃分成k個較小

動態規劃貪心演算法

貪心演算法: 典型的應用有Huffman樹,直接構造兩個最小的連續相加,得到目標樹。 目標函式f=sum(li*wi);就是權重乘以葉節點的深度求和再求最小值。 如果目標函式修改為f=sum(li+wi)或max(li+wi)或任意函式g(li,wi),是否可以求解呢?

動態規劃貪心演算法之揹包問題理解

一.揹包問題 引用書上關於0-1揹包和部分揹包的闡述: 二.貪心與動態規劃區別 關於紅色矩形部分解釋為什麼0-1不能使用貪心演算法,是因為當你選擇一個物品時,整個物品的大小都需要計算,然而揹包的的大小又是固定的,那麼剩下的揹包大小與剩下的物品之間

動態規劃貪心演算法區別

不同點: 貪心演算法: 1.貪心演算法中,作出的每步貪心決策都無法改變,因為貪心策略是由上一步的最優解推導下一步的最優解,而上一部之前的最優解則不作保留。 2.由(1)中的介紹,可以知道貪心法正確的條件是:每一步的最優解一定包含上一步的最優解。

動態規劃or貪心演算法--剪繩子/切割杆

需求一: 剪繩子,將長度為n的繩子剪成若干段,求各段長度乘積的最大值分析: 1、動態規劃    設f(n)代表長度為n的繩子剪成若干段的最大乘積,如果第一刀下去,第一段長度是i,那麼剩下的就需要剪n-i,那麼f(n)=max{f(i)f(n-i)}。而f(n)的最優解對應著f

遞迴、分治策略、動態規劃以及貪心演算法之間的關係

引言 最近集中研究計算智慧,其中涉及到遞迴和動態規劃,動態規劃實現中又用到了遞迴,忽然發現這兩個概念的差別分得不太清楚。索性把遞迴、分治策略、動態規劃、貪婪選擇之間的聯絡與區別都一併搞清楚吧。 1、分治策略(Divide and Conquer)

從最短路徑談動態規劃貪心演算法

一言以蔽之:動態規劃,從全域性最優考慮;最短路徑,從當前最優考慮。 先考慮下面的圖 可以很容易地看出,如果使用貪心演算法,從a到e的路線將是:a->b->c->d->e,而採用動態的規劃的路線則是:a->c->e。 貪心演算法的優點是程

動態規劃貪心演算法的比較

動態規劃和貪心演算法都是一種遞推演算法 均有區域性最優解來推導全域性最優解 不同點: 貪心演算法: 1.貪心演算法中,作出的每步貪心決策都無法改變,因為貪心策略是由上一步的最優解推導下一步的最優解,而

再論動態規劃貪心演算法

      個人感覺貪心演算法是一個尋找規律的過程,事實上這種規律有時候是很難找到的,並且還面臨一個重大的問題是我們找的規律(一個極值解)並不一定是最值解,需要推理證明極值等於最值。     而動態規劃是一個尋找子問題的過程,有點類似分制演算法,但是動態規劃重在去掉重複的子問

(轉)動態規劃貪心演算法區別

動態規劃和貪心演算法的區別動態規劃和貪心演算法都是一種遞推演算法 均有區域性最優解來推導全域性最優解 不同點: 貪心演算法: 1.貪心演算法中,作出的每步貪心決策都無法改變,因為貪心策略是由上一步的最優解推導下一步的最優解,而上一部之前的最優解則不作保留。 2.由(1)中的介紹,可以知道貪心法正確的條件是:每

動態規劃貪心演算法區別

本來這次是該總結動態規劃的,但在學習過程中發現動態規劃和上一節的貪心演算法有很大聯絡,而在演算法設計過程中主要是對兩種演算法的選擇,所以決定這次以對比的方式做總結,既可以更深入地瞭解動態規劃,又可以對

leetcode 53. 最大子序和(治法動態規劃

給定一個整數陣列 nums ,找到一個具有最大和的連續子陣列(子陣列最少包含一個元素),返回其最大和。示例:輸入: [-2,1,-3,4,-1,2,1,-5,4], 輸出: 6 解釋: 連續子陣列 [4,-1,2,1] 的和最大,為 6。 進階:如果你已經實現複雜度為 O(n

劍指offer(面試題14): 動態規劃貪心演算法求解最優化問題

題目 給定一長為n的繩子,要求把繩子剪成m段(m,n都是整數且n>1,m>1),每段繩子的長度記為k[0], k[1], k[2]…,k[m]。請問k[0]*k[1]*k[2]….*k[m]可能的最大乘積是多少?例如,當繩子的長度是8時,可以剪成2

JavaScript演算法模式——動態規劃貪心演算法

動態規劃   動態規劃(Dynamic Programming,DP)是一種將複雜問題分解成更小的子問題來解決的優化演算法。下面有一些用動態規劃來解決實際問題的演算法: 最少硬幣找零   給定一組硬幣的面額,以及要找零的錢數,計算出符合找零錢數的最少硬幣數量。例如,美國硬幣面額有1、5、10、25這四種

動態規劃治法貪心算法以及遞歸的再一次深刻理解和體會

規劃 動態 分治法 每次體會算法都有新的感覺,刷題越多,對算法的理解感覺也就越深刻。下面我們來重新體會下分治法,動態規劃,貪心法,遞歸的理解。1.分治法: 將問題分成單獨的階段,每個階段互相不幹擾很獨立,如10米長的木棍,切成10段,每段去解決每一段的問題。(階段沒有關系)2.貪心法 站