状态压缩DP POJ 1699解题报告

来源:互联网 发布:mysql数据库备份方法 编辑:程序博客网 时间:2024/05/16 01:03

http://acm.pku.edu.cn/JudgeOnline/problem?id=1699

今天在做POJ 1699时,明显感觉用DP可以解,但是始终找不到合适的状态方程和子结构。在discuss中看到有人讨论用“状态压缩dp”求解比较方便,于是花了一下午时间去查找状态dp的资料,在上一篇(zz)中看到了一篇讲解非常详细的介绍,于是就开始来分析POJ 1699。

看到这一题的第一直觉是全排列所有的字符串,通过回溯肯定能求出最优解,但是时间复杂度可能不能AC。于是试着寻找最优子结构,试着用dp来解。

假设min是最优解,最直接考虑的是min=min{ 第i个串排在最后时得到字串长度}。

假设dp[si][i]表示状态si下以i字符串结尾最优值(best sequence),其中si是二进制位表示的集合,二进制位串的长度(len(si))根据字符串的个数来n确定。若si[k]=0表示当前状态集合不包含字符串k,即第k个字符串还未放置,用k!=si表示。

例如,n=4,si=00000~01111。

则min = min {dp[2^n-1][i]},

                       n表示字符串的个数,0<i<n。

                       2^n-1表示所有的字符串都已经放置,

                       dp[2^n-1][i]表示在所有的字符串都已经放置好的情况下,以第i个字符串结尾是的字符串长度。

则有:dp[si][i] = min {dp[sj][j] + m(i,j)},

                  sj = si&(~(1<<i)),表示对当前状态集出去i,得到一个规模更小的子问题sj。

                  对每一个j属于sj,求出子问题dp[sj][j]。

这里存在很多重复的子问题,比如当si=01101,i=0时,这时sj = 01100,这时对j=2,j=3都属于集合sj,因为sj[2]和sj[3]都为1。

于是求解dp[s0][0]需要求解dp[s2][2]和dp[s3][3]。

而当si=01110,i=1时,这时sj=01100,于是求dp[s1][1]同样需要求dp[s2][2]和dp[s3][3]。

考虑到上述递归形式和重复子问题,于是考虑用记忆化dp(记忆化递归搜索)来求解问题。