1计数问题
我们再举一个例子来研究动态规划,看下面的题:
题目描述:有n个无区别的物品,将他们划分成不超过m组,共有多少种划分数?
限制条件:1<=m<=n<=1000
举例:n=4,m=3,输出为4(1+1+2,1+3,2+2)
把这个问题简单概括为n的m划分。
我们来分析下怎样用动态规划解决这种排列组合类的问题。
既然就两个变量,我们就用
dp[i][j]
来表示j的i划分数,然后i从1到m,j从1到n两层循环就行了。
再来看递推式:将j划分成i份,那先取出个k,再将j-k划分成i-1份就行了,那么递推式是:
dp[i][j]=求和(k从0到j):dp[i-1][j-k]
,先不说这个复杂度,这个递推式是错的,因为物品无区别,1+2+1和1+1+2是一种划分,我们的递推式重复计数了。
再仔细思考下?
题目中是划分成不超过m组,那么划分方案分两种,j的i划分为(1)j的i-1划分+(2)j就分成i份。
第一个好表达,第二个怎么用dp表示呢?第一个是把i改变了,第二个应该改变j了,我减小j使得j减去一个数为第二个的数,因为分成i份,每份都大于0,我把每份都减去1后,可能还是i份,也可能小于i份了,他们的总和是j-i,这就是j-i的i划分啊!
最后,递推式为:
dp[i][j]=dp[i][j-i]+dp[i-1][j]
这样复杂度为O(mn),代码也就好写了(注意循环中j小于i时递推式没有第二项)
2复杂计数问题
问题描述:有n种物品,第i种物品有ai个,不同的物品有区别,但相同物品没区别,问:从物品中取出m个,有多少种取法?
限制条件:1<=n,m,ai<=1000
举例:n=m=3,a={1,2,3},输出6{0+0+3,0+1+2,0+2+1,1+0+2,1+1+1,1+2+0}
这个问题看着就复杂,上面就一种物品,这个这么多物品,我们举的简单的例子都要想一会儿才有答案。
因为同种物品没区别,所以我们只考虑取了几种物品就行,用dp[i][j]表示从前i种物品中取车j个的组合总数。
递推式怎样分析呢?
因为不同物品有差异,这次我们可以按照上面最初的想法:先从i-1种物品中取出j-k个,再吧第i种物品中的k个添加进来,k最多为a[i],但也不能比j还大。
所以递推式为:
,这个是正确的,但是k最差可能到m,所以复杂度为O(mn),能不能像上篇博文那样把k化简呢?试试。
通过一系列的转化,最后把k消掉了,其中用的思想和上篇博文相同:先展开k,再缩小k。
3总结
用了两篇文章把最基础的动态规划问题分别相信解释了一下,主要是递推公式的推导,大家仔细琢磨一下就会发现,其实内在思路都是差不多的,当然动态规划还有很多很难的,例如状态压缩dp问题,以后再慢慢学习。