1. 程式人生 > 其它 >【基本演算法】窮舉演算法

【基本演算法】窮舉演算法

技術標籤:Java基礎窮舉演算法雞兔同籠問題百錢買百雞問題

1、什麼是窮舉?

窮舉演算法是最簡單的一種演算法,其依賴於計算機的強大計算能力,來窮盡每一種可能的情況,從而達到求解問題的目的。

窮舉演算法效率並不高,但適用於一些沒有明顯規律可循的場景。基本思想是從所有可能的情況中搜索正確的答案,在使用窮舉演算法時,需要明確問題的答案的範圍,這樣才可以在指定範圍內搜尋答案。指定範圍之後,就可以使用迴圈語句和條件判斷語句逐步驗證候選答案的正確性,從而得到需要的正確答案。其執行步驟如下:

(1). 對於一種可能的情況,計算其結果;

(2).判斷結果是否滿足要求,如果不滿足則執行第(1)步來搜尋下一個可能的情況;如果滿足要求,則表示尋找到一個正確的答案。

2、窮舉演算法應用

雞兔同籠

雞兔同籠問題最早記載於1500年前的《孫子算經》,是我國古代一個非常有名的問題,原文如下:今有雞兔同籠,上有三十五頭,下有九十四足,問雞兔各幾何?

翻譯過來的意思是在一個籠子裡關著若干只雞和若干只兔,從上面數共有35個頭;從下面數共有94只腳。問籠中雞和兔的數量各是多少?題目要計算雞的數量和兔的數量,通過分析可以知雞的數量應該為0~35之間的數。

基於該思路,可以使用窮舉法來逐個判斷是否符合條件,從而得到答案。暴力窮舉.....,Java程式碼實現如下:

public class Test {
    /** 雞的數量、兔子數量 */
    public static int chicken, rabbit;

    /** 窮舉.... */
    public static boolean getAmount(int header, int foot) {
        boolean flag = false;
        int j; // j 兔子數量
        for (int i = 0; i < header; i++) { // i 雞的數量
            j = header - i;
            if (foot == (2 * i + 4 * j)) {
                chicken = i;
                rabbit = j;
                flag = true;
            }
        }
        return flag;
    }

    /** 測試結果:有雞23只, 有兔12個 */
    public static void main(String[] args) {
        // 上有三十五頭,下有九十四足,問雞兔各幾何?
        if (getAmount(35, 94)) {
            System.out.println("有雞" + chicken + "只, 有兔" + rabbit + "個");
        }
    }
}

當然,雞兔同籠問題,最簡單的是使用解方程的思路了,設定x,y分別代表雞和兔,foot,header分別代表足和頭,那麼可以得到一個一元二次方程組:x + y = header;2*x + 4*y = foot; 消元求解可得:y = (foot - 2*header)/2 ; x =header-y; 這樣也解出了雞兔同籠的問題。

百錢買百雞問題

百錢買百雞是一個非常經典的不定方程問題,最早源於我國古代的《算經》,這是古代著名數學家張丘建首次提出的。百錢買百雞問題的原文如下:雞翁一,值錢五,雞母一,值錢三,雞雛三,值錢一,百錢買百雞,問翁、母、雛各幾何?

翻譯過來的意思是公雞5文錢1只,母雞3文錢1只,小雞3只1文錢,如果用100文錢買100只雞,那麼公雞、母雞和小雞各應該買多少隻呢?使用解方程的思路的話,該問題中,有三個變數:公雞數量、母雞數量和小雞數量,分別設為x、y和z。這三者應該滿足如下關係:x+y+z=100;5x+3y+z/3=100; 這裡有三個變數,兩個方程,因此是一個不定方程問題,這將導致求解的結果不只一個。

當然,這裡使用窮舉法來逐個判斷是否符合條件,從而得到答案,很暴力很粗魯,Java程式碼實現如下:

public class Test {
    /**
     * 列印結果:
     *  有雞翁0只, 有雞母25只, 有雞雛75只
     *  有雞翁4只, 有雞母18只, 有雞雛78只
     *  有雞翁8只, 有雞母11只, 有雞雛81只
     *  有雞翁12只, 有雞母4只, 有雞雛84只
     **/
    public static void main(String[] args) {
        getChickenAmount(100, 100);
    }

    /**
     * 雞翁一,值錢五,雞母一,值錢三,雞雛三,值錢一,百錢買百雞,問翁、母、雛各幾何?
     */
    public static void getChickenAmount(int money, int amount) {
        int k; // k 雞雛
        for (int i = 0; i < amount; i++) { // i 雞翁
            for (int j = 0; j < amount; j++) { // j 雞母
                k = amount - i - j;
                if (k > 0 && (k % 3 == 0) && (5 * i + 3 * j + k / 3) == money) {
                    System.out.println("有雞翁" + i + "只, 有雞母" + j + "只, 有雞雛" + k + "只");
                }
            }
        }
    }
}

3、窮舉的優缺點

窮舉的優點就是直觀,會粗魯的列舉出每一種情況,這也成為了其致命的缺點,會造成程式執行效率低,程式碼冗餘等問題,一般不推薦使用。

參考書籍:《Java常用演算法手冊(第3版)》