整數劃分的遞歸實現算法,並輸出所有劃分(Java)

整數劃分的遞歸實現算法,並輸出所有劃分(Java)

先打廣告,所有的算法作業我都會把代碼更新在我的GitHub上
滑技工廠——Homework-AlgorithmAnalysis

希望大家能打個小⭐⭐,謝謝

依舊是算法作業,這次是整數劃分問題。

在網上找了半天,大多都是求整數劃分有多少種,很少求詳細的劃分情況。

有也都是C語言版的,並找不到Java的。

於是我便想出一個Java的(其實差不多,只是如果有人需要Java版的方便搜到)

問題

說明一下問題,什麼是整數劃分?

n=m1+m2+…+mi; (其中mi爲正整數,並且1 <= mi <= n),則{m1,m2,…,mi}爲n的一個劃分。

如果{m1,m2,…,mi}中的最大值不超過m,即max(m1,m2,…,mi)<=m,則稱它屬於n的一個m劃分。這裏我們記n的m劃分的個數爲f(n,m);

舉個例子,當n=6時我們可以獲得以下這幾種劃分:
6=6
6=5+1
6=4+2
6=4+1+1
6=3+3
6=3+2+1
6=3+1+1+1
6=2+2+2
6=2+2+1+1
6=2+1+1+1+1
6=1+1+1+1+1+1

分析

這樣子也非常容易看出來,n的整數劃分是建立在n-1的基礎上的,所以是可以有遞推公式的。

單個參數我們很難找到遞推式,於是我們增加一個參數m,表示一個劃分結果中的最大加數。

根據n和m的關係,考慮以下幾種情況:

  1. 當n=1時,不論m的值爲多少(m>0),只有一種劃分即{1};

  2. 當m=1時,不論n的值爲多少,只有一種劃分即n個1,{1,1,1,…,1};

  3. 當n=m時,根據劃分中是否包含n,可以分爲兩種情況:

    (a)劃分中包含n的情況,只有一個即{n};

    (b)劃分中不包含n的情況,這時劃分中最大的數字也一定比n小,即n的所有(n-1)劃分。 因此 q(n,n) =1 + q(n,n-1);

  4. 當n<m時,由於劃分中不可能出現負數,因此就相當於q(n,n);

  5. 但n>m時,根據劃分中是否包含最大值m,可以分爲兩種情況:

    (a)劃分中包含m的情況,即{m, {x1,x2,…xi}}, 其中{x1,x2,… xi} 的和爲n-m,因此這情況下爲q(n-m,m)

    (b)劃分中不包含m的情況,則劃分中所有值都比m小,即n的(m-1)劃分,個數爲q(n,m-1);

因此 q(n, m) = q(n-m, m)+q(n,m-1);
在這裏插入圖片描述

代碼

求整數劃分種數

/*
     * @Title division
     * @Description 整數劃分方法
     * @author 滑技工廠
     * @Date 2020/3/8
     * @param [n, m]   n->要劃分的整數  m->最大加數
     * @return int 輸出有多少種劃分
     * @throws
     */
    public static int division(int n, int m) {
        if (n < 1 || m < 1)
            return 0;
        if (n == 1 || m == 1)
            return 1;
        //最大加數如果大於n 則另最大加數爲n
        if (n < m)
            return division(n, n);
        //m=n,則從
        if (n == m)
            return division(n, m - 1) + 1;

        return division(n, m - 1) + division(n - m, m);

    }

求具體劃分情況


	static int mark[] = new int[100];//記錄分解情況
    static int n;
    /*
     * @Title divide
     * @Description 輸出劃分
     * @author 滑技工廠
     * @Date 2020/3/8
     * @param [now, k, pre]
     * @return void
     * @throws
     */
    public static void divide(int now, int k, int pre) {
        int i;
        //數組長度大於n就返回
        if (now > n) return;

        if (now == n) {

            System.out.printf("%d=", n);
            for (i = 0; i < k - 1; i++) {
                System.out.printf("%d+", mark[i]);
            }
            System.out.printf("%d\n", mark[i]);
        } else {
            for (i = pre; i > 0; i--) {
                if (i <= pre) {
                    mark[k] = i;
                    now += i;
                    divide(now, k + 1, i);
                    now -= i;
                }
            }
        }
    }

以6爲例,得到的結果爲
在這裏插入圖片描述

完結撒花✿,贈人玫瑰。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章