前段时间看到csdn论坛的数据结构与算法版上有人问了这么一个问题:
给定n个石子,其重量为a1,a2...,an,要求将其划分为m堆,每一份划分的费用定义为这堆石头中最大重量与最小重量的差的平方。总划分费用等于各堆费用之和。 输入:n m 及a1,a2...,an ,输出:sum
我搜了一下,发现同样的问题问过不止一遍:
http://topic.csdn.net/u/20091216/00/34ca0d8d-9d56-4ed4-821b-5171e1a67679.html?50332
http://topic.csdn.net/u/20091212/01/bcd82df3-ef2a-4ccd-bd1f-af8588e8e114.html
这道题显然用DP可以解决:
对所有石子的重量从小到大进行排序,设排序后的重量为a[1], a[2]....a[n]。
设f[n,m]为n个石子分成m堆后的最小费用,我们可以列出DP转移方程:
f[j,m] = min_i{f[i,m-1] + (a[j]-a[i])^2} (i<j)
这样我们得到了一个O(m*n^2)的算法。(这里小小的解释一下为什么要排序:因为每个堆的费用只记录最大值和最小值的平方,中间的值完全没有用处,所以应该把所有中间的值都放到这个堆中,使它们不会增大其他堆的费用。当排完序后,每一堆就是序列中的某一段。)
然而,这样的复杂度并不是很好,考虑到m最大可到n,当n大到1000级别的时候,程序运行将会是很慢,我们需要优化它。事实上,这道题中每一堆的费用是满足一些特殊性的。
设从i到j的石子的费用为w[i,j]=(a[j]-a[i])^2。对于这个w[i