问题
将长度为n的序列s=[x1,x2,…,xn]进行合并,每次合并将相邻的两个元素a和b合并为一个新的元素c,并且c=a+b,合并的代价也为a+b。经过n−1次合并后,序列s被合并为1个数字,这个过程的代价是之前所有合并的代价总和。求出将序列s合并为一个数字的最小合并代价。合并过程如图:
例如序列s=[1,2,3],合并过程有[1,2,3]→[3,3]→[6]和[1,2,3]→[1,5]→[6],最终合并代价为9,11。
解法
设sum(i,j)为序列中区域s[i,j]的所有元素之和,f(i,j)为合并区域s[i,j]的最小代价,其中1≤i≤j≤n。因此有如下状态转移方程:
f(i,j)=⎩⎨⎧0+∞min{f(i,k)+f(k+1,j)+sum(i,k)+sum(k+1,j)}(initialize)(initialize)(loop)i,j∈[0,n]i,j∈[0,n]i,j,k∈[1,n]i=ji=ji≤k≤j (1) 初始化,对于同一个元素s[i,i]不需要合并,因此f(i,i)=0;
(2) 初始化,对于不同的元素s[i,j]需要合并,设未知的f(i,j)=+∞;
(3) 将s[i,k]和s[k+1,j]这两个区域的元素合并(i≤k≤j),因此f(i,j)=min{f(i,k)+f(k+1,j)+sum(i,k)+sum(k+1,j)},选择该范围中所有结果的最小值即可;
f(1,n)即为序列s的最小合并代价。该算法的时间复杂度是O(n2)。
石子合并
源码
MinimumMergeCost.h
MinimumMergeCost.cpp
测试
MinimumMergeCostTest.cpp