題目鏈接:點擊打開鏈接
①.若是劃分多個整數可以存在相同的:(詳見函數 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;
}