小学期学的算法和做OJ题的各种经验总结
有 n 个无区别的物品 , 将他们分成 不超过 m 堆, 问有多少种分法 ?
- d i j d_{ij} dij表示将数字i 分成j 份的方案数(初始化 d 0 j = 1 d_{0j}=1 d0j=1,其他为0),有2种类型:
-
带0的划分可以少一份。如4 = 0 + 2 + 2 = 2 + 2,把4分成3份 = 把4分成2份
即把i分成j份 = 把i分成j-1份。所以 d i j d_{ij} dij 包含 d i , j − 1 d_{i,\ j-1} di, j−1
-
不带0的划分,推到带0的划分上,每份均摊少一个1。
如 5 = 1 + 2 + 2,与 5-3 = 1-1 + 2-1 + 2-1 => 2 = 0 + 1 + 1的效果相同
即把i分成j份 = 把 i - j 分成j份(每份均摊一个1)。所以 d i j d_{ij} dij包含 d i − j , j d_{i-j,\ j} di−j, j -
因为每个数只有这两种划分方法,综上, d i j = d i , j − 1 + d i − j , j d_{ij}=d_{i,\ j-1}+d_{i-j,\ j} dij=di, j−1+di−j, j
注意边缘条件,如i<j时 d i j d_{ij} dij状态转化为 d i , j − 1 d_{i,\ j-1} di, j−1
int n,m;
int d[MAXN][MAXM];
int main() {
d[0][0] = 1;
for(int i = 1; i <= m; i++) d[0][i] = 1;
for(int i = 1; i<=n; i++){
for(int j = 1; j<=m; j++){
if(i>=j) d[i][j] = d[i][j-1] + d[i-j][j];
else d[i][j] = d[i][j-1];//份数比数字大,可以降
}
}
}