线性分割问题(The Linear Partion Problem)
- 问题描述
给定数组 A[1, 2, ..., n] 和正整数 k, 要求将 A 分割为至多 k 段(即,将 A 至多切 k - 1刀),使得各段的元素之和的最大值最小。
例如,设 A = [1, 2, 3, 4, 5, 6, 7, 8, 9],k = 3。若将 A 分割为1, 2, 3 | 4,5,6 | 7, 8, 9,则各段元素之和分别为 6, 15, 24,最大为24; 若将 A 分割为1, 2, 3 , 4,5 | 6, 7 | 8, 9,则各段元素之和分别为 15, 13, 17,最大为17,因此第二种分割方式要好于第一种(事实上,这也是最优的分割方式)。
- 动态规划解
把上述问题记为 Problem(A[1, ..., n], k),把子问题 Problem(A[1, ..., m], j) 的最优值记为 opt[m, j], 则显然有边界条件
因为把A[1, ..., m] 分为一段只有一种分法。
由于 A[1, ..., m] 最多只能被分为 m 段, 所以有:
当 1 < j <= m 时, 有递推关系式
- c++代码
1 #include<vector> 2 #include<list> 3 #include<iterator> 4 #include<iostream> 5 #include<utility> 6 7 /* 8 输入: 9 [beg, end) ------ 数组所在的区间 10 k ------ 段数 11 输出: 12 一个列表,其元素是各个分段点的位置。 13 */ 14 template<class Iter> 15 std::list<int> linear_partion(const Iter &beg, const Iter &end, int k) 16 { 17 typedef typename std::iterator_traits<Iter>::value_type value_type; 18 typedef std::vector<std::vector<value_type> > Matrix; 19 20 int n = end - beg; 21 if(k > n) 22 k = n; 23 Matrix opt(n + 1, std::vector<value_type>(k + 1)); //存储最优值的DP表 24 Matrix d(n + 1, std::vector<value_type>(k + 1)); //存储分段点位置的DP表 25 26 //边界条件 27 opt[1][1] = *beg; 28 Iter it = beg + 1; 29 for(int m = 2; m <= n; ++m, ++it) 30 opt[m][1] = opt[m - 1][1] + *it; 31 32 for(int j = 2; j <= k; ++j) 33 { 34 for(int m = 1; m < j; ++m) 35 { 36 opt[m][j] = opt[m][m]; 37 d[m][j] = d[m][j - 1]; 38 } 39 40 for(int m = j; m <= n; ++m) 41 { 42 opt[m][j] = opt[m][j - 1]; 43 d[m][j] = d[m][j - 1]; 44 for(int i = 1; i < m; ++i) 45 { 46 value_type cost = std::max(opt[i][j - 1], opt[m][1] - opt[i][1]); 47 if(opt[m][j] > cost) 48 { 49 opt[m][j] = cost; 50 d[m][j] = i; 51 } 52 } 53 } 54 } 55 56 //输出分段点到一个list 57 std::list<int> index_seg; 58 int j = k; 59 int m = n; 60 while(j > 0) 61 { 62 if(m < j) 63 j = m; 64 index_seg.insert(index_seg.begin(), m); 65 m = d[m][j]; 66 j -= 1; 67 } 68 return index_seg; 69 } 70 71 72 int main() 73 { 74 //int a[] = {1,2,3,4,5,6,7,8,9}; 75 int a[] = {1,1,1,1,1,1,1,1,1}; 76 auto id1 = linear_partion(a + 0, a + 9, 3); 77 for(auto &x : id1) 78 std::cout << x << ","; 79 std::cout << std::endl; 80 81 int b[] = {1,2,3,4,5,6,7,8,9}; 82 auto id2 = linear_partion(b + 0, b + 9, 3); 83 for(auto &x : id2) 84 std::cout << x << ","; 85 std::cout << std::endl; 86 87 }
结果分别为
3, 6, 9
和
5,7,9.
老实为人,踏实为学