幾種常用的算法簡介

jopen 10年前發布 | 26K 次閱讀 算法

1、窮舉法

窮舉法是最基本的算法設計策略,其思想是列舉出問題所有的可能解,逐一進行判別,找出滿足條件的解。

窮舉法的運用關鍵在于解決兩個問題:

如何列舉所有的可能解;

如何判別可能解是否滿足條件;

在運用窮舉法時,容易出現的問題是可能解過多,導致算法效率很低,這就需要對列舉可能解的方法進行優化。

以題1041--純素數問題為例,從1000到9999都可以看作是可能解,可以通過對所有這些可能解逐一進行判別,找出其中的純素數,但只要稍作分析,就會發現其實可以大幅度地降低可能解的范圍。根據題意易知,個位只可能是3、5、7,再根據題意可知,可以在3、5、7的基礎上,先找出所有的二位純素數,再在二位純素數基礎上找出三位純素數,最后在三位純素數的基礎上找出所有的四位純素數。

2、分治法

分治法也是應用非常廣泛的一種算法設計策略,其思想是將問題分解為若干子問題,從而可以遞歸地求解各子問題,再綜合出問題的解。

分治法的運用關鍵在于解決三個問題:

確定分治規則,即如何分解問題。

確定終結條件,即問題分解到什么狀態時可以直接求解。

確定歸納方法,即如何由子問題的解得到原問題的解。這一步并不總是需要的,因為對某些問題來說,并不需要對子問題的解進行復雜的歸納。

我們熟知的如漢諾塔問題、折半查找算法、快速排序算法等都是分治法運用的典型案例。

以題1045--Square Coins為例,先對題意進行分析,可設一個函數f(m, n)等于用面值不超過n2 的貨幣構成總值為m的方案數,則容易推導出:

f(m, n) = f(m-0*n*n, n-1)+f(m-1*n*n, n-1)+f(m-2*n*n, n-1)+...+f(m-k*n*n, n-1) 
這里的k是幣值為n2 的貨幣最多可以用多少枚,即k=m/(n*n)。

也很容易分析出,f(m, 1) = f(1, n) = 1

對于這樣的題目,一旦分析出了遞推公式,程序就非常好寫了。所以在動手開始寫程序之前,分析工作做得越徹底,邏輯描述越準確、簡潔,寫起程序來就會越容易。

3、動態規劃法

動態規劃法多用來計算最優問題,動態規劃法與分治法的基本思想是一致的,但處理的手法不同。動態規劃法在運用時,要先對問題的分治規律進行分析,找出終結子問題,以及子問題向父問題歸納的規則,而算法則直接從終結子問題開始求解,逐層向上歸納,直到歸納出原問題的解。

動態規劃法多用于在分治過程中,子問題可能重復出現的情況,在這種情況下,如果按照常規的分治法,自上向下分治求解,則重復出現的子問題就會被重復地求解,從而增大了冗余計算量,降低了求解效率。而采用動態規劃法,自底向上求解,每個子問題只計算一次,就可以避免這種重復的求解了。

動態規劃法還有另外一種實現形式,即備忘錄法。備忘錄的基本思想是設立一個稱為備忘錄的容器,記錄已經求得解的子問題及其解。仍然采用與分治法相同的自上向下分治求解的策略,只是對每一個分解出的子問題,先在備忘錄中查找該子問題,如果備忘錄中已經存在該子問題,則不須再求解,可以從備忘錄中直接得到解,否則,對子問題遞歸求解,且每求得一個子問題的解,都將子問題及解存入備忘錄中。

例如,在題1045--Square Coins中,可以采用分治法求解,也可以采用動態規劃法求解,即從f(m, 1)和f(1, n)出發,逐層向上計算,直到求得f(m, n)。

在競賽中,動態規劃和備忘錄的思想還可以有另一種用法。有些題目中的可能問題數是有限的,而在一次運行中可能需要計算多個測試用例,可以采用備忘錄的方法,預先將所有的問題的解記錄下來,然后輸入一個測試用例,就查備忘錄,直接找到答案輸出。這在各問題之間存在父子關系的情況下,會更有效。例如,在題 1045--Square Coins中,題目中已經指出了最大的目標幣值不超過300,也就是說問題數只有300個,而且各問題的計算中存在重疊的子問題,可以采用動態規劃法,將所有問題的解先全部計算出來,再依次輸入測試用例數據,并直接輸出答案。

4、回溯法

回溯法是基于問題狀態樹搜索的求解法,其可適用范圍很廣。從某種角度上說,可以把回溯法看作是優化了的窮舉法。回溯法的基本思想是逐步構造問題的可能解,一邊構造,一邊用約束條件進行判別,一旦發現已經不可能構造出滿足條件的解了,則退回上一步構造過程,重新進行構造。這個退回的過程,就稱之為“回溯”。

回溯法在運用時,要解決的關鍵問題在于:

如何描述局部解。

如何擴展局部解和回溯局部解。

如何判別局部解。

回溯法的經典案例也很多,例如全排列問題、N后問題等。

5、貪心法

貪心法也是求解最優問題的常用算法策略,利用貪心法策略所設計的算法,通常效率較高,算法簡單。貪心法的基本思想是對問題做出目前看來最好的選擇,即貪心選擇,并使問題轉化為規模更小的子問題。如此迭代,直到子問題可以直接求解。

基于貪心法的經典算法例如:哈夫曼算法、最小生成樹算法、最短路徑算法等。

但是,貪心法的運用是有條件的,必須能夠證明貪心選擇能夠導出最優解,且轉化出的子問題與原問題是同性質的問題,才能使用貪心法求解。

一個比較經典的貪心法求解的問題就是找硬幣問題:有1、2、5、10、20、50、100七種面值的硬幣,要支付指定的金額,問怎么支付所用的硬幣個數最少。這是一個非常日常化的問題,憑直覺我們會想到,盡可能先用大面值的硬幣,這就是“貪心選擇”,而在這個問題上,這個貪心選擇也是正確的。

6、限界剪枝法

限界剪枝法是求解較復雜最優問題的一種算法策略,與回溯法類似的是,限界剪枝法也是在問題狀態空間樹上進行搜索,但回溯法是搜索一般解,而限界剪枝法則是搜索最優解。限界剪枝法的基本思想是通過找出權值函數的上下界函數,以下界函數來指導搜索的方向,以上界函數來幫助剪除一些不可能含有最優解的分枝。

關于算法和算法策略的討論是一個非常龐大的話題,幾乎每個問題點都能擴展出一大堆可討論的內容和案例。我實在不知道該怎樣用簡短的幾篇文字就能夠把這個話題說透,這里只能蜻蜓點水地對競賽中經常用到的幾種策略做一極為簡略的介紹。

也許我們可以在以后的文章中,針對具體的題目進行算法和策略的分析,效果可能會更好。

原文地址:http://blog.csdn.net/woods2001/article/details/4292518

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!