正整数拆分问题

来源:互联网 发布:互联网产品经理 知乎 编辑:程序博客网 时间:2024/06/13 23:36

Problem 1

求将正整数N无序拆分成若干个不大于M的正整数的方案数

f[i][j]表示i拆分成若干个不大于j的正整数的方案数
考虑第i个数的大小是否为j
f[i][j]=f[ij][j]+f[i][j1]
是为前者,否为后者
显然可以将空间优化成一维
时间复杂度为O(nm),空间复杂度O(n)

Problem 2

求将正整数N无序拆分成M个正整数的方案数

有序拆分即为组合问题,此略

Algorithm 1

由于其无序性,我们默认枚举拆分的正整数由小到大
f[i][j][k]表示i拆分成j个正整数,第j个为k的方案数
枚举下一个数llk,则f[i+l][j+1][l]+=f[i][j][k]
这样dp(由当前状态枚举更新未来状态)俗称刷表,刷表的好处是若当前状态不合法,此次无需花费转移的复杂度
但是算一下,总复杂度为O(n3m)

Algorithm 2

考虑优化上述dp
我们换一种dp方式,枚举已有状态来更新当前状态,转移式为f[i][j][k]+=f[ik][j1][l]lk
显然f[ik][j1][l]可以做前缀和,使得转移复杂度优化为O(1)
那么总复杂度优化为O(n2m),由此可见,这样dp的好处是可以做前缀和之类的优化

但是时间复杂度仍然不够优

Algorithm 3

我们多花费了一维状态来限制无序的条件,事实上可以换一种思路
f[i][j]表示i拆分成j个正整数的方案数
f[i][j]=f[i1][j1]+f[ij][j]
在已选数集中增加一个1,方案数为f[i1][j1]
将已选数集中每个数加1,方案数为f[ij][j]
我们甚至可以把空间优化成一维的
时间复杂度O(nm),空间复杂度O(n)

Algorithm 4

233其实Problem 2可以转化为Problem 1

如图,将数的大小形象成高度,从左到右依次是M个正整数
其中高度总和为N
首先每个数非零,于是将最底层用M的代价填满,总和还剩N-M
从下往上看,剩下每一行的数的个数单调递减
那么每一行相当于一个拆分,问题变为将N-M拆分成若干个不小于M的正整数
可以套用Problem 1的DP

原创粉丝点击