整數劃分問題問:「將 n 寫成若干正整數之和(順序不計)有多少種方法?」本文從組合數學定義、動態規劃遞推構造、二維/一維空間實現、模運算處理、生成函數理論視角五個維度,提供完整解題框架。
n、最大劃分數 m、模數 Mn 的不超過 m 個部分的劃分數 mod Mn=4, m=3 → 劃分:4、3+1、2+2、2+1+1 → 共 4 種設 p(n, m) = 將 n 劃分為不超過 m 個正整數的方法數。
p(n, m) = p(n, m-1) + p(n-m, m) (n ≥ m > 0) // 邊界條件 p(0, m) = 1 // 空劃分算 1 種 p(n, 0) = 0 (n>0) // 正整數不可劃分為 0 個部分 p(n, m) = 0 (n<0) // 負數無劃分
p(n, m-1):不使用 數字 m 的劃分(所有部分 ≤ m-1)p(n-m, m):至少使用一個 m,剩餘 n-m 繼續劃分(部分仍 ≤ m)#include <stdio.h>
#include <string.h>
#define MAX_N 1000
#define MAX_M 1000
int n, m, M;
int dp[MAX_N + 1][MAX_M + 1];
int partition_2d() {
memset(dp, 0, sizeof(dp));
dp[0][0] = 1; // 關鍵初始化
for (int i = 1; i <= m; i++) { // 部分數上限
for (int j = 0; j <= n; j++) { // 目標和
dp[i][j] = dp[i-1][j]; // 不用 i
if (j >= i) {
dp[i][j] = (dp[i][j] + dp[i][j-i]) % M; // 至少用一個 i
}
}
}
return dp[m][n];
}
int main() {
n = 4; m = 3; M = 10000;
printf("result = %d\n", partition_2d()); // 4
return 0;
}
int partition_1d() {
static int dp[MAX_N + 1];
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 1; i <= m; i++) {
// 正序遍歷 j (i 到 n) —— 完全背包模式!
for (int j = i; j <= n; j++) {
dp[j] = (dp[j] + dp[j-i]) % M;
}
}
return dp[n];
}
關鍵洞察: 整數劃分 本質上是完全背包問題:物品為 1..m,每種重量=價值=面值,無限件,恰裝滿容量 n 的方案數。
# n=4, m=3 劃分: 4 | 3+1 | 2+2 | 2+1+1 結果: 4 # n=5, m=5 (無限制劃分數 p(5)) 劃分: 5 | 4+1 | 3+2 | 3+1+1 | 2+2+1 | 2+1+1+1 | 1+1+1+1+1 結果: 7 # n=10, m=10 p(10) = 42 # n=100, m=100, M=1e9+7 需用長整型/大數,結果: 792070839 (mod 1e9+7)
劃分數生成函數:
P(x) = ∏_{k=1}^{∞} 1/(1 - x^k)
= 1 + x + 2x² + 3x³ + 5x⁴ + 7x⁵ + 11x⁶ + ...
// 係數即 p(n)
p(n) = Σ (-1)^{k-1} p(n - k(3k-1)/2)p(n) ~ 1/(4n√3) exp(π√(2n/3))| 變體 | 定義 | 遞推修改 |
|---|---|---|
| 限制最大部分值 | 每部分 ≤ K | 外層循環 i=1..K |
| 限制部分個數 | 恰好 m 部分 | dp[i][j][k] 三維:前 i 數、和 j、k 部分 |
| 不同部分劃分 | 各部分互不相同 | 01 背包模式:逆序 j |
| 奇數部分劃分 | 所有部分為奇數 | 外層 i=1,3,5... |
(a + b) % M 防溢出,M 可為質數或任意整數M=0 時輸出完整值,需大整數庫(GMP/手寫高精度)dp[0]=1 是「空劃分」語義,不可漏| 方案 | 時間 | 空間 | 適用場景 |
|---|---|---|---|
| 二維 DP | O(nm) | O(nm) | 教學、需中間狀態、m 較小 |
| 一維 DP(推薦) | O(nm) | O(n) | 生產、大 n、嵌入式 |
| 歐拉遞推 | O(n√n) | O(n) | 無限制劃分 p(n)、理論研究 |
整數劃分問題將組合計數、動態規劃、生成函數、數論漸近分析串聯成一條完美知識鏈。掌握「完全背包視角」與「一維正序遍歷」模式,不僅能秒殺劃分數,更能觸類旁通硬幣找零、郵票面值設計、資源分配方案計數等同構問題。