ITPub博客

首页 > Linux操作系统 > Linux操作系统 > DP算法解释

DP算法解释

原创 Linux操作系统 作者:it01 时间:2019-01-08 07:36:06 0 删除 编辑

稍微解释下:
BitSet isSolved,isSuit
中的isSolved.get(n,k)表示(n,k)是否已经求解过
isSuit.get(n,k)为true表示n个人可能为k场
简记isSuit.get(n,k)为s[n,k].

n个人能够比k场实际上是问: n能否存在一个分解 xi(xi>0)使得
Sum{xi} =n, Sum{xi*xj: i!=j} =k;
注意到 Sum{xi}*Sum{xi} = Sum{xi*xj}

= Sum{xi*xi} +2 *Sum{xi*xj: i!=j}
又易知 n <=Sum{xi*xi} <= n*n
故可得k的取值范围为: 0<=k <= n*(n-1)/2
因此我们只需判断 k在 [0,n*(n-1)/2]中的取值.

下面我们来推导DP状态转移方程:

假设n存在分解 n = Sum{xi: 1<=i<=L}
使得 k = Sum{xi*xj: 1<=i,j<=L,i!=j}
有: k = Sum{x1*xi: i!=1} +Sum{xi*xj: 2<=i,j<=L,i!=j}
= x1*(n-x1) +Sum{xi*xj:2<=i,j<=L,i!=j}
可以看出: {xi: 2<=i<=L}是 k- x1*(n-x1)的一个满足条件的分解
从而我们有:
s[n,k] = OR{s[n-m,k-m*(n-m)] : 1<=m其中OR表示逻辑或运算.

6.11添加:对offset()方法的说明
对于每一个n,我只需计算s[n,0],s[n,1],....,s[n,n*(n-1)/2]
很容易可以想到可以用一个二维boolean数组来保存s的值:
boolean[][] s =new boolean[MAX+1][]; //用MAX+1是因为把n=0的情形也包含进出了
然后:
s[n] =new boolean[n*(n-1)/2+1]
不过,这里我没有采用boolean数组,而是采用一个BitSet(后面的C代码用的是一个char数组,然后用其每一个bit保存一个值).
BitSet可以看成是一个一维bit数组,但这里我们就要考虑如何将原来的二维boolean数组"拉直"成一维数组了:
显然,我们只要知道s[n]对应的BitSet位置就可以了,这就是offset方法要干的事.
由于s[0]要占1个位,s[1]要占一个位,....,更一般的:
s[m]的取值是0到m*(m-1)/2
因此,s[m]要占 1+m*(m-1)/2 个位 (呵呵,不要把这个1漏了)

这样,我们可以计算s[n]的在BitSet的偏移位置应该是前s[0],...s[n-1]所占位置的总和,也就是:
Sum{1+m*(m-1)/2 : 0<=m<=n-1}
唔,这个求和公式比1加到100要难一些(当然,如果你和我一样是学数学的话就不会觉得难了)
总而言之,求和的结果就是:

引用

offset(n) =Sum{1+m*(m-1)/2 : 0<=m<=n-1}
=n*(n-1)*(n-2)/6 +n

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12467/viewspace-148155/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2002-05-25

  • 博文量
    197
  • 访问量
    136870