第10篇 ACM/ICPC競賽之算法策略算法
ACM/ICPC競賽其實就是算法設計和編碼的競賽,熟悉各類經常使用算法和算法設計策略並能靈活運用是很是必要的。
這裏對幾種在競賽中常常用到的算法設計策略作一簡單的介紹。
1、窮舉法
窮舉法是最基本的算法設計策略,其思想是列舉出問題全部的可能解,逐一進行判別,找出知足條件的解。
窮舉法的運用關鍵在於解決兩個問題:
如何列舉全部的可能解;
如何判別可能解是否知足條件;
在運用窮舉法時,容易出現的問題是可能解過多,致使算法效率很低,這就須要對列舉可能解的方法進行優化。
以題hduoj 1041--純素數問題爲例,從1000到9999均可以看做是可能解,能夠經過對全部這些可能解逐一進行判別,找出其中的純素數,但只要稍做分析, 就會發現其實能夠大幅度地下降可能解的範圍。根據題意易知,個位只多是3、5、7,再根據題意可知,能夠在3、5、7的基礎上,先找出全部的二位純素 數,再在二位純素數基礎上找出三位純素數,最後在三位純素數的基礎上找出全部的四位純素數。
2、分治法
分治法也是應用很是普遍的一種算法設計策略,其思想是將問題分解爲若干子問題,從而能夠遞歸地求解各子問題,再綜合出問題的解。
分治法的運用關鍵在於解決三個問題:
肯定分治規則,即如何分解問題。
肯定終結條件,即問題分解到什麼狀態時能夠直接求解。
肯定概括方法,即如何由子問題的解獲得原問題的解。這一步並不老是須要的,由於對某些問題來講,並不須要對子問題的解進行復雜的概括。
咱們熟知的如漢諾塔問題、折半查找算法、快速排序算法等都是分治法運用的典型案例。
以題hduoj 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)。
在競賽中,動態規劃和備忘錄的思想還能夠有另外一種用法。有些題目中的可能問題數是有限的,而在一次運行中可能須要計算多個測試用例,能夠採用備忘錄的方 法,預先將全部的問題的解記錄下來,而後輸入一個測試用例,就查備忘錄,直接找到答案輸出。這在各問題之間存在父子關係的狀況下,會更有效。例如,在題 hduoj 1045--Square Coins中,題目中已經指出了最大的目標幣值不超過300,也就是說問題數只有300個,並且各問題的計算中存在重疊的子問題,能夠採用動態規劃法,將 全部問題的解先所有計算出來,再依次輸入測試用例數據,並直接輸出答案。
4、回溯法
回溯法是基於問題狀態樹搜索的求解法,其可適用範圍很廣。從某種角度上說,能夠把回溯法看做是優化了的窮舉法。回溯法的基本思想是逐步構造問題的可能解, 一邊構造,一邊用約束條件進行判別,一旦發現已經不可能構造出知足條件的解了,則退回上一步構造過程,從新進行構造。這個退回的過程,就稱之爲「 回溯」。
回溯法在運用時,要解決的關鍵問題在於:
如何描述局部解。
如何擴展局部解和回溯局部解。
如何判別局部解。
回溯法的經典案例也不少,例如全排列問題、N後問題等。
5、貪心法
貪心法也是求解最優問題的經常使用算法策略,利用貪心法策略所設計的算法,一般效率較高,算法簡單。貪心法的基本思想是對問題作出目前看來最好的選擇,即貪心選擇,並使問題轉化爲規模更小的子問題。如此迭代,直到子問題能夠直接求解。
基於貪心法的經典算法例如:哈夫曼算法、最小生成樹算法、最短路徑算法等。
可是,貪心法的運用是有條件的,必須可以證實貪心選擇可以導出最優解,且轉化出的子問題與原問題是同性質的問題,才能使用貪心法求解。
一個比較經典的貪心法求解的問題就是找硬幣問題:有1、2、5、10、20、50、100七種面值的硬幣,要支付指定的金額,問怎麼支付所用的硬幣個數最 少。這是一個很是平常化的問題,憑直覺咱們會想到,儘量先用大面值的硬幣,這就是「貪心選擇」,而在這個問題上,這個貪心選擇也是正確的。
6、限界剪枝法函數
限界剪枝法是求解較複雜最優問題的一種算法策略,與回溯法相似的是,限界剪枝法也是在問題狀態空間樹上進行搜索,但回溯法是搜索通常解,而限界剪枝法則是 搜索最優解。限界剪枝法的基本思想是經過找出權值函數的上下界函數,如下界函數來指導搜索的方向,以上界函數來幫助剪除一些不可能含有最優解的分枝。
關於算法和算法策略的討論是一個很是龐大的話題,幾乎每一個問題點都能擴展出一大堆可討論的內容和案例。我實在不知道該怎樣用簡短的幾篇文字就可以把這個話題說透,這裏只能走馬觀花地對競賽中常常用到的幾種策略作一極爲簡略的介紹。
也許咱們能夠在之後的文章中,針對具體的題目進行算法和策略的分析,效果可能會更好。測試
未完待續###優化