窮舉法的應用

窮舉法的基本思想

窮舉法(枚舉法)的基本思想是:列舉出所有可能的情況,逐個判斷有哪些是符合問題所要求的條件,從而得到問題的全部解答。
它利用計算機運算速度快、精確度高的特點,對要解決問題的所有可能情況,一個不漏地進行檢查,從中找出符合要求的答案。
用窮舉算法解決問題,通常可以從兩個方面進行分析。
(1)問題所涉及的情況:問題所涉及的情況有哪些,情況的種數可不可以確定。把它描述出來。應用窮舉時對問題所涉及的有限種情形必須一一列舉,既不能重複,也不能遺漏。重複列舉直接引發增解,影響解的準確性;而列舉的遺漏可能導致問題解的遺漏。
(2)答案需要滿足的條件:分析出來的這些情況,需要滿足什麼條件,才成爲問題的答案。把這些條件描述出來。
只要把這兩個方面分析好了,問題自然會迎刃而解。
窮舉通常應用循環結構來實現。在循環體中,根據所求解的具體條件,應用選擇結構實施判斷篩選,求得所要求的解。
窮舉法的程序框架一般爲:
cnt=0; // 解的個數初值爲0
for(k=<區間下限>;k<=<區間上限>;k++) // 根據指定範圍實施窮舉
if (<約束條件>) // 根據約束條件實施篩選
{
cout<<(<滿足要求的解>); // 輸出滿足要求的解
cnt++; // 統計解的個數
}
有些問題沒有明確的區間限制,可根據問題的具體實際試探性的從某個數開始,增值窮舉,對每一個數作一判斷,若滿足條件即輸出結果,結束窮舉。

               下面爲幾個窮舉法的經典案例及代碼實現(Java)

【案例1】硬幣方案

有50枚硬幣,可能包括4種類型:1元、5角、1角和5分。
已知50枚硬幣的總價值爲20元,求各種硬幣的數量。
例如:2、34、6、8就是一種方案。而2、33、15、0是另一個可能的方案,顯然方案不唯一。
編寫程序求出類似這樣的不同的方案一共有多少種?
代碼:

public void show_01() {
    int coin_num = 50, count = 0;// 硬幣數量
    int num_yuan, num_5jiao, num_1jiao, num_fen;
    for (num_yuan = 0; num_yuan < 50; num_yuan++)
     for (num_5jiao = 0; num_5jiao < 100; num_5jiao++)
      for (num_1jiao = 0; num_1jiao < 500; num_1jiao++)
        for (num_fen = 0; num_fen < 1000; num_fen++) {
          if ((num_yuan + 0.5 * num_5jiao + 0.1 *                num_1jiao + 0.01 * num_fen) == 20) {
           System.out.println(num_yuan + "," + num_5jiao + ","+ num_1jiao + "," + num_fen);
            count++;
            }
        }
        System.out.println("共有" + count + "種組合方式!");
    }

【案例2】4位分段和平方數

一個4位自然數分爲前後兩個2位數,若該數等於所分兩個2位數和的平方,則稱爲4位分段和平方數。例如,2025=(20+25)2。
編寫程序求出所有4位分段和平方數。
代碼:

public void show_02() {
        int i, j, num, count = 0;
        for (num = 1000; num <= 9999; num++) {
            i = num / 100;
            j = num % 100;
            if ((i + j) * (i + j) == num) {
                count++;
                System.out.println(num);
            }
        }
        System.out.println("共有"+count+"個這樣的4位分段和平方數");
    }

【案例3】三個三位數

將1、2、…、9共9個數分成三組,分別組成三個三位數,且使這三個三位數構成1:2:3的比例,試求出所有滿足條件的三個三位數。
例如:三個三位數192、384、576滿足以上條件。
代碼:

    //這三個變量之後的案例還會用到
    private int[] v = new int[10];
    private int[] vis = new int[10];
    private int[] bk = new int[10];
   //*******************************
    public void show_03() {
        int num, num2, num3, count = 0;
        for (int i = 0; i < 10; i++)
            v[i] = 0;
        for (num = 100; num < 999; num++) {
            num2 = 2 * num;
            num3 = 3 * num;
            if (num2 <= 999 && num3 <= 999) {
                if (judge(num) && judge(num2)&& judge(num3)) {
               System.out.println(num + "," + num2 + "," + num3);
                    count++;
                }
            }
            for (int i = 0; i < 10; i++)
                v[i] = 0;
        }
        System.out.println("共有" + count + "種組合");
    }

    private Boolean judge(int n) {
        int i = n % 10;
        int j = n / 10;
        j = j % 10;
        int k = n / 100;
        if (v[i] != 0)
            return false;
        else
            v[i] = 1;
        if (v[j] != 0)
            return false;
        else
            v[j] = 1;
        if (v[k] != 0)
            return false;
        else
            v[k] = 1;
        return true;
    }

【案例4】完美運算式

把數字1、2、…、9這9個數字填入以下含加減乘除與乘方的綜合運算式中的9個□中,使得該式成立
□^□+□□÷□□-□□×□=0
要求數字1,2,…、9這9個數字在式中都出現一次且只出現一次。
代碼:

    public void show_04() {
        int a, b, c, i, j, k;
        for (a = 1; a <= 9; a++)
            for (b = 1; b <= 9; b++)
                for (c = 1; c <= 9; c++)
                    for (i = 12; i <= 98; i++)
                        for (j = 12; j <= 98; j++)
                            for (k = 12; k <= 98; k++) {
        if (i % j == 0) { // i/j不爲小數
        for (int t = 0; t < 10; t++) { // 初始化數組
            v[t] = 0;
        }
        int ab = (int) Math.pow(a, b);
        if (_04judge1(a) && _04judge1(b)&& _04judge1(c)
         &&  _04judge2(i)&& _04judge2(j) && _04judge2(k)
         && (ab + i / j - k * c == 0)) {
           System.out.println(a + "^" + b + "+"+ c 
           + "/" + i + "-" + j + "*"+ k + "=0");
        }
       }
     }
    }
    private Boolean _04judge1(int n) {
        if (v[n] == 0) {
            v[n] = 1;
        } else
            return false;
        return true;
    }

    private Boolean _04judge2(int n) {
        int i, j;
        i = n % 10;
        j = n / 10;
        if (v[i] == 0) {
            v[i] = 1;
        } else
            return false;
        if (v[j] == 0) {
            v[j] = 1;
        } else
            return false;
        return true;
    }

【案例5】神奇算式

由4個不同的數字,組成的一個乘法算式,它們的乘積仍然由這4個數字組成。
比如:210 x 6 = 1260,8 x 473 = 3784,27 x 81 = 2187都符合要求。
如果滿足乘法交換律的算式算作同一種情況,那麼一共有多少種滿足要求的算式呢?
代碼:

public void show_05() {
        int cnt = 0;
        for (int i = 1000; i <= 10000; i++) {
            for (int a = 0; a < 10; a++) { // 初始化數組
                vis[a] = 0;
            }

            if (judge2(i)) {
                for (int a = 0; a < 10; a++) { // 數組賦值
                    bk[a] = vis[a];
                }
                for (int j = 1; j <= 98; j++) {
                    for (int a = 0; a < 10; a++) { // 數組賦值
                        vis[a] = bk[a];
                    }
                    if (i % j != 0) {// 要求能整除
                        continue;
                    }

                    int k = i / j; // 既得k,j兩個數字
                    if (j > k) { // 由乘法交換律可得,除去重複項
                        continue;
                    }
                    if (judge1(j, k)) {
                        System.out.println(j + "*" + k + " = " + i);
                        cnt++;
                    }
                }
            }
        }
        System.out.println("共有" + cnt + "種");
    }

    Boolean judge1(int x, int y) {//判斷數字組成是否與i組成相同,相同返回1
        do {
            if (vis[x % 10] == 0) {
                return false;
            }
            vis[x % 10]--;
            x /= 10;
        } while (x != 0);
        do {
            if (vis[y % 10] == 0) {
                return false;
            }
            vis[y % 10]--;
            y /= 10;
        } while (y != 0);
        return true;
    }

    Boolean judge2(int x) {//判斷i是否含重複數字,有則返回0,否則返回1
        do {
            if (vis[x % 10] != 0) {
                return false;
            }
            vis[x % 10]++;
            x /= 10;
        } while (x != 0);
        return true;
    }

【案例6】排它平方數

小明正看着 203879 這個數字發呆。
原來,203879 * 203879 = 41566646641
這有什麼神奇呢?仔細觀察,203879 是個6位數,並且它的每個數位上的數字都是不同的,並且它平方後的所有數位上都不出現組成它自身的數字。
請找出具有這樣特點的所有6位數。
代碼:

public void show_06() {
        int num = 0, count = 0;
        // BigInteger x ;
        double result;
        for (int a = 1; a <= 9; a++)
            for (int b = 1; b <= 9; b++)
                for (int c = 1; c <= 9; c++)
                    for (int d = 1; d <= 9; d++)
                        for (int e = 1; e <= 9; e++)
                            for (int f = 1; f <= 9; f++) {
                                //數組賦值
                                for (int t = 0; t <10;t++) {
                                    v[t] = 0;
                                }
                                if (judge3(a)&&judge3(b)
                                && judge3(c)&&judge3(d)
                                && judge3(e) && judge3(f)) {
                                    num = a * 100000 +
                                     b * 10000 + c * 1000 + d
                                            * 100 + e * 10 + f;
                                    result=num*num;//平方之後的結果
                                    if (judge4(num)) {
                                        System.out.println(num +
                                         "平方的結果爲:"+ result);
                                        count++;
                                    }

                                }

                            }
        System.out.println("共有" + count + "個這樣的6位數");
    }

    private Boolean judge3(int n) {

        if (v[n] == 0)
            v[n] = 1;
        else
            return false;

        return true;
    }

    private Boolean judge4(double n)// 用於判斷平方結果
    {
        long s_n = (long) n;

        BigInteger num1 = BigInteger.valueOf(s_n);
        BigInteger num2 = BigInteger.valueOf(s_n);
        BigInteger b_n = num1;
        BigInteger temp;
        BigInteger t = num1.multiply(num1);// 兩數相乘
        do {
            temp = t.remainder(BigInteger.valueOf(10));// t%10
            System.out.println(" " + temp);
            b_n =b_n.divide(BigInteger.valueOf(10));// b_n /= 10;
            if (!judge3(Integer.valueOf(temp + "")))
                return false;
        } while (b_n != BigInteger.valueOf(0));
        return true;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章