枚舉法,又稱窮舉法,個人理解就是程序運行狀態是可以別遍歷的,遍歷算法執行每一個狀態,最終會找到一個最優的可行解。
舉個栗子,今天中午我和同事商量去哪吃飯的問題,我們都不確定去哪一家,于是我就一家一家的數,臊子面,黃燜雞米飯,牛肉拉面,雞湯面......當我說到羊肉泡饃時,我同事眼前一亮,說,走羊肉泡饃走起。。。典型的窮舉法,有么有?
再如計算100以內的所有奇數,就可以采用枚舉法。
那么,適用于窮舉法求解的問題必須滿足哪些條件呢?
(1)、可 預先確定每個解的元素N的個數;
(2)、解元素S1、S2....Sn的可能址為一個連續的值域;
應用窮舉法的場合有: 求不定方程、排列組合、暴力破解算法;
由此可見窮舉法的特點是什么呢?
1、窮舉法的特點:
(1)、可供選擇的答案或元素的范圍是有限的,如今天中午吃什么的問題,我們可供選擇的店就那么多家,并不是無限的;
(2)、可能做了很多無用功、浪費了寶貴的時間,所以導致效率比較低;
(3)、可供選擇的答案或元素是同一類事物,我們選擇去吃飯的地方都是餐館;
(4)、得到的結果肯定是正確的;
(5)、通常會涉及到求極值(如最大,最小,等)。
所以最終得到的結論是:并不是所有的問題都可以使用窮舉法來求解,只有問題的答案個數不是太多時,并且在可以接受的時間內得到結果時才可以使用窮舉法。?
2、窮舉法的優點:?
(1)、算法簡單,比較直觀,易于理解;
(2)、最后一定會得到一個結果。
(3)、從全局觀點使用窮舉法,計算量容易過大,如果在局部地方使用窮舉法,計算的效率會顯著提高。
3、窮舉法的缺點:
(1)、由于窮舉法的特點,將可供選擇的元素逐一的進行篩選,也就造成了程序在運行的時間比較長;
(2)、當可供選擇的答案過大時,可能導致返回結果的時間太長或者其他問題;
4、窮舉法的基本思路:
(1)、確定窮舉對象,窮舉范圍和判定條件;
(2)、逐一枚舉可能的解,驗證是否時問題的解。
5、求解方法和步驟:
(1)、確定可選擇的范圍內的所有解的集合;
(2)、抽象出答案包含的參數,確定每個參數的數據范圍;
(3)、對解的每個參數的數據范圍進行循環遍歷;
(4)、對每次的循環,根據題意給定的范圍判斷是否為解;
(5)、優化程序、以便縮小搜索范圍,提高程序的效率。
6、窮舉法的列舉方式:
(1)順序列舉: 是指答案范圍內的各種情況很容易與自然數對應甚至就是自然數,可以按自然數的變化順序去列舉。
(2)排列列舉: 有時答案的數據形式是一組數的排列,列舉出所有答案所在范圍內的排列,為排列列舉。
(3)組合列舉: 當答案的數據形式為一些元素的組合時,往往需要用組合列舉。組合是無序的。
舉例:百錢百雞問題用窮舉法來求解:
這個數學問題的數學方程可列出如下:
Cock+Hen+Chick=100
Cock*5+Hen*3+Chick/3=100
顯然這是個不定方程,適用于窮舉法求解。依次取Cock值域中的一個值,然后求其他兩個數,滿足條件就是解。那么該如何用程序語言來完成呢。
最終終端打印的結果為:
前面已經提到,由于窮舉法的特點,當問題的可選范圍變大時,循環嵌套的層數越多,計算效率就相對的變低了,此時作為程序員就要對算法做出優化;
如:上面的計算百錢買百雞的代碼中,循環體執行了21*34*101 = 72114次,那么近過分析,從數學的角度來考慮這個問題:根據題意,5x+3y=z/3=100, ? ? x+y+z=100可以消去一個未知數z,最終得到:7x+4y=100, ? x+y+z=100,于是只要枚舉公雞x(最多只有14只),最終就可以求出y和z,可用程序表示:
優化后的代碼,只循環了14次,此時的效率明顯提升了,由于電腦的運行速度相當快,其實我并沒有什么明顯的感覺,但是這個問題被無限放大,比如循環次數達到了千萬次時優化就會有很明顯的效果了,那么總結一下如何做出優化:
7、優化策略:
(1)、減少循環次數;
(2)、合理選擇循環的變量;
(3)、注意枚舉的順序;
(4)、減少判斷每種情況的時間。