线性分割问题(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.

 

 

 

posted @ 2013-06-03 12:50  半亩梨花  阅读(1085)  评论(0编辑  收藏  举报