问题:在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,合并的花费为这相邻两堆石子的数量之和。试设计算法,计算出将N堆石子合并成一堆的最小花费。
在解题之前,介绍一下“四边形不等式优化”,关于这个优化方法的证明,csdn以及网上其他博客上详细介绍了很多,查了很多资料还是有点一知半解,再次归纳简述如下:
即在DP问题中,经常可以解得如下的转移方程:
dp[i][j]=min{dp[i][k]+dp[k+1][j]+cost[i][j]}
求解这个方程需要for一遍i,for一遍j,再for一遍k,则算法时间复杂度为O(n^3),此时如果该方程满足四边形不等式,那就可以优化为O(n^2)。四边形不等式描述为(详细证明可以参考https://blog.csdn.net/noiau/a...):
对于( a < b <= c< d )
如果有 f[a][c] + f[b][d] <= f[b][c] + f[a][d],那么f满足四边形不等式。
由四边形不等式可以给出2个定理(不作证明):
给出两个定理:
如果上述的cost函数同时满足区间包含单调性和四边形不等式性质,那么函数dp也满足四边形不等式性质 。
定义s(i,j)表示 dp(i,j) 取得最优值时对应的下标(即 i≤k≤j 时,k 处的 dp 值最大,则 s(i,j) = k此时有如下定理:假如dp(i,j)满足四边形不等式,那么s(i,j)单调,即 s(i,j)≤s(i,j+1)≤s(i+1,j+1)
那么状态转移方程可以由 m[i,j] = min{m[i,k] + m[k,j]} (i ≤ k ≤ j)转化为
m[i,j] = min{m[i,k] + m[k,j]} (s[i,j-1] ≤ k ≤ s[i+1,j])
那么在对k循环的时候,就不比每次都从当前的i遍历到j,而是以s[i,j-1]和s[i+1,j]替换,即缩小了k的取值范围,s[i,j] 的值在 m[i,j] 取得最优值时,保存和更新,因此 s[i,j-1] 和 s[i+1,j] 都在计算 dp[i][j-1] 以及 dp[i+1][j] 的时候已经计算出来了。
当区间长度为(L+1)时,在n个元素中,所有可能的k全部遍历次数叠加为:
(s[2,L+1]-s[1,L])+(s[3,L+2]-s[2,L+1])…+(s[n-L+1,n]-s[n-L,n-1])=s[n-L+1,n]-s[1,L] ≤ n,所以遍历k产生的代价可以省略,复杂度降低到O(n^2)。
准备工作完毕回到石子合并问题,如果所有石子排成一列,那么解法很简单,DP转移公式易得为:
当石子是环形排列,例如0,1,2,3,4,5 五堆石子排成圆环&#x