正整数拆分问题

4 篇文章 0 订阅

Problem 1

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

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

Problem 2

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

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

Algorithm 1

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

Algorithm 2

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

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

Algorithm 3

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

Algorithm 4

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

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

Problem 3

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

可以发现,Problem 3与Problem 2相比,去掉了“恰好M个加数”的限制。复杂度能不能更优秀呢?
这个问题等价于:
有N种物品,第i种重量为i,每种都有无限个,求装满容量为N的背包的方案数。
考虑平衡规划,对于 in0.5 i ≤ n 0.5 ,直接暴力做完全背包, O(n1.5) O ( n 1.5 )
对于 i>n0.5 i > n 0.5 ,所选物品数量不会超过 n0.5 n 0.5 ,采用类似上面思想的dp。
f[i][j] f [ i ] [ j ] 表示 i i 个数和为j的方案数,则转移为
f[i][j]=f[i1][j(n0.5+1)]+f[i][ji] f [ i ] [ j ] = f [ i − 1 ] [ j − ( n 0.5 + 1 ) ] + f [ i ] [ j − i ]
显然也是 O(n1.5) O ( n 1.5 )
最后再把两部分合并即可。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值