整數劃分(三) NYIST 571

題目鏈接:點擊打開鏈接


1.將 n 劃分成每個數不大於 m 的劃分方案數:

  ①.若是劃分多個整數可以存在相同的:(詳見函數 f1 )
     (dp1[n][k] 表示整數 n 的劃分中,每個數不大於 k 的劃分數。)
    1).當n == 1時,只能劃分爲1個數,該數爲1,故劃分方案數爲1,dp1[n][k] = 1
    1).當k == 1時,只能劃分爲n個數,均爲1,故劃分方案數爲1,dp1[n][k] = 1
    2).當n < k時,被劃分的數爲n,能劃分出的最大數爲n,故 dp1[n][k] = dp1[n][n]
    3).當n == k時,方案數爲最大數等於n,即只取一個n,和最大數爲n - 1的方案數之和,故 dp1[n][k] = dp1[n][n] = dp1[n][n-1] + 1
    4).不符合上述條件時:
      dp1[n][k] = dp1[n][k-1] + dp1[n-k][k]
     則劃分數可以分爲兩種情況:
       a.劃分中每個數都小於 k,相當於每個數不大於 k - 1, 故劃分數爲 dp1[n][k-1].
       b.劃分中有一個數爲 k. 那就在 n 中減去 k ,剩下的就相當於把 n - k 進行劃分,故劃分數爲 dp1[n-k][k]

  ②.若是劃分多個不同的整數:(詳見函數 f4 )
     (dp4[n][k] 表示整數 n 的劃分中,每個數不大於 k 的劃分數。)
    1).當n == 1時,只能劃分出1個數,故 dp4[n][k] = 1
    2).當n > 1 && k == 1時,最大數爲1,因此劃分出 1 個 1 後無法從 n - 1 中劃分出不同的整數,故dp4[n][k] = 0
    3).當n < k時,被劃分的數爲n,能劃分出的最大數爲n,故 dp4[n][k] = dp4[n][n]
    4).當n == k時,方案數爲最大數等於n,即只取一個n,和最大數爲n - 1的方案數之和,故 dp4[n][k] = dp4[n][n] = dp4[n][n-1] + 1
    5).不符合上述條件時:
      dp4[n][k] = dp4[n][k-1] + dp4[n-k][k-1]
     同樣劃分情況分爲兩種情況:
       a.劃分中每個數都小於 k ,相當於每個數不大於 k - 1 ,劃分數爲 dp4[n][k-1].
       b.劃分中有一個數爲 k. 在 n 中減去 k ,剩下相當對 n - k 進行劃分,並且每一個數不大於 k - 1 ,故劃分數爲 dp4[n-k][k-1]

2.將 n 劃分成 k 個數的劃分法:(詳見函數 f2 )
     (dp[n][k] 表示整數 n 的劃分中,將 n 劃分成 k 個正整數之和的劃分數。)
    1).當k == 1時,則劃分出1個數,該數爲n,故dp2[n][k] = 1
    2).當n == k時,則劃分出n個數,均爲1,故dp2[n][k] = 1
    3).當n < k時,無法將n劃分成k個數,故dp2[n][k] = 0
    4).不符合上述條件時:
      dp2[n][k] = dp2[n-k][k]+ dp2[n-1][k-1]
     方法可以分爲兩類:
      第一類: n 份中不包含 1 的分法,爲保證每份都 >= 2,可以先拿出 k 個 1 分到每一份,然後再把剩下的 n- k 分成 k 份即可,分法有: dp2[n-k][k]
      第二類: n 份中至少有一份爲 1 的分法,可以先那出一個 1 作爲單獨的1份,剩下的 n- 1 再分成 k- 1 份即可,分法有:dp2[n-1][k-1]。

3.將 n 劃分成若干個奇數的和:(詳見函數 f3 )
     (dp3[n][k] 表示整數 n 的劃分中,每個數不大於 k 的劃分數。)
    1).當k == 1 || k == 2時,可以用來劃分的奇數只有1,所以種數也只能是一種。
    2).當n < k的時候,多出的部分根本劃分不到,所以種數爲:dp[n][n]
    3).當n == k時,根據k的奇偶性判定是否劃分k,dp[n][n] = dp[n][k-1-(k&1))] + (k&1);
    4).不符合上述條件時:
       dp3[n][k] = dp3[n][k-1-!((k-1)&1))] + dp3[n-k][k-!(k&1)]
      則劃分數可以分爲兩種情況:
       a.劃分中每個數都小於 k,相當於每個數不大於 k - 1, 若 k - 1 爲奇數,則劃分出的每個數不大於 k - 1 ,否則劃分處的每個數不大於 k - 2 ,故劃分數爲 dp[n][k-1-!((k-1)&1))].
       b.劃分中有一個數爲 k. 那就在 n中減去 k ,剩下的就相當於把 n - k 進行劃分,若k爲奇數,則劃分出的每個數不大於 k ,否則劃分出的每個數不大於 k - 1 ,故劃分數爲 dp3[n-k][k-!(k&1)]


代碼如下:

#include <cstdio>

const int N = 55;
int dp1[N][N], dp2[N][N], dp3[N][N], dp4[N][N];

int f1(int n, int k) // 劃分整數n時,劃分出的最大數不超過k的劃分數
{
    if(dp1[n][k]) return dp1[n][k];
    else if(n == 1 || k == 1) return dp1[n][k] = 1;
    else if(n < k) return dp1[n][n] = f1(n, n);
    else if(n == k) return dp1[n][n] = f1(n, n - 1) + 1;
    else return dp1[n][k] = f1(n, k - 1) + f1(n - k, k);
}

int f2(int n, int k) // 劃分整數n時,將n劃分成k個正整數之和的劃分數
{
    if(dp2[n][k]) return dp2[n][k];
    else if(k == 1 || n == k) return dp2[n][k] = 1;
    else if(n < k) return dp2[n][k] = 0;
    else return dp2[n][k] = f2(n - 1, k - 1) + f2(n - k, k);
}

int f3(int n, int k) // 劃分整數n時,將n劃分成若干個奇正整數之和,劃分出的最大數不超過k的劃分數
{
    if(dp3[n][k]) return dp3[n][k];
    else if(k == 1 || k == 2) return 1;
    else if(n < k) return dp3[n][n] = f3(n, n);
    else if(n == k) return dp3[n][n] = f3(n, k - 1 - (k & 1)) + (k & 1);
    else return dp3[n][k] = f3(n, k - 1 - !((k - 1) & 1)) + f3(n - k, k - !(k & 1));
}

int f4(int n, int k) // 劃分整數n時,將n劃分成若干不同整數之和,劃分出的最大數不超過k的劃分數
{
    if(dp4[n][k]) return dp4[n][k];
    else if(n == 1) return dp4[n][k] = 1;
    else if(k == 1) return dp4[n][k] = 0;
    else if(n < k) return dp4[n][n] = f4(n, n);
    else if(n == k) return dp4[n][n] = f4(n, n - 1) + 1;
    else return dp4[n][k] = f4(n, k - 1) + f4(n - k, k - 1);
}

int main()
{
    // freopen("in", "r", stdin);
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        printf("%d\n", f1(n, n));   // 將n劃分成若干正整數之和的劃分數
        printf("%d\n", f2(n, m));   // 將n劃分成k個正整數之和的劃分數
        printf("%d\n", f1(n, m));   // 將n劃分成最大數不超過k的劃分數
        printf("%d\n", f3(n, n));   // 將n劃分成若干個奇正整數之和的劃分數
        printf("%d\n", f4(n, n));   // 將n劃分成若干不同整數之和的劃分數
        puts("");
    }
    return 0;
}


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