HDU 3480 DP 斜率优化 Division

把n个数分成m段,每段的值为(MAX - MIN)2,求所能划分得到的最小值。

依然是先从小到大排个序,定义状态d(j, i)表示把前i个数划分成j段,所得到的最小值,则有状态转移方程:

d(j, i) = min { d(j-1, k) + (ai - ak+1)2 | 0 ≤ k < i }

 

设 l < k < i,且由k转移得到的状态比由l转移得到的状态更优。

有不等式:

整理成斜率形式:

 

后面的就可以相当于套模板了,不过这里要用滚动数组优化一下空间。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 10000 + 10;
 8 const int maxm = 5000 + 10;
 9 const int INF = 0x3f3f3f3f;
10 
11 int n, m;
12 
13 int a[maxn];
14 int d[2][maxn];
15 
16 int head, tail;
17 int Q[maxn];
18 
19 int cur;
20 
21 int inline Y(int x) { return d[cur^1][x] + a[x+1] * a[x+1]; }
22 
23 int inline DY(int p, int q) { return Y(q) - Y(p); }
24 
25 int inline DX(int p, int q) { return a[q+1] - a[p+1]; }
26 
27 int main()
28 {
29     freopen("in.txt", "r", stdin);
30 
31     int T; scanf("%d", &T);
32     for(int kase = 1; kase <= T; kase++)
33     {
34         scanf("%d%d", &n, &m);
35         for(int i = 1; i <= n; i++) scanf("%d", a + i);
36         sort(a + 1, a + 1 + n);
37 
38         memset(d[0], 0x3f, sizeof(d[0]));
39         d[0][0] = 0;
40         cur = 0;
41         for(int i = 1; i <= m; i++)
42         {
43             cur ^= 1;
44             head = tail = 0;
45             Q[tail++] = 0;
46             for(int j = 1; j <= n; j++)
47             {
48                 while(head + 1 < tail && DY(Q[head], Q[head+1]) <= DX(Q[head], Q[head+1]) * 2 * a[j]) head++;
49                 while(head + 1 < tail && DY(Q[tail-1], j) * DX(Q[tail-2], Q[tail-1]) <= DY(Q[tail-2], Q[tail-1]) * DX(Q[tail-1], j)) tail--;
50                 Q[tail++] = j;
51                 d[cur][j] = d[cur^1][Q[head]] + (a[j]-a[Q[head]+1]) * (a[j]-a[Q[head]+1]);
52             }
53         }
54         printf("Case %d: %d\n", kase, d[cur][n]);
55     }
56 
57     return 0;
58 }
代码君

 

下面是四边形不等式优化的代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 10000 + 10;
 8 const int maxm = 5000 + 10;
 9 const int INF = 0x3f3f3f3f;
10 
11 int n, m;
12 
13 int a[maxn];
14 int d[maxm][maxn], s[maxm][maxn];
15 
16 int main()
17 {
18     int T; scanf("%d", &T);
19     for(int kase = 1; kase <= T; kase++)
20     {
21         scanf("%d%d", &n, &m);
22 
23         for(int i = 1; i <= n; i++) scanf("%d", a + i);
24         sort(a + 1, a + 1 + n);
25 
26         memset(s, 0, sizeof(s));
27         for(int i = 1; i <= m; i++)
28         {
29             int j;
30             for(j = 1; j <= i; j++) d[i][j] = 0;
31             for(; j <= n; j++) d[i][j] = INF;
32         }
33 
34         for(int i = 1; i <= n; i++)
35         {
36             s[1][i] = 0;
37             d[1][i] = (a[i] - a[1]) * (a[i] - a[1]);
38         }
39 
40         for(int i = 2; i <= m; i++)
41         {
42             s[i][n+1] = n;
43             for(int j = n; j > i; j--)
44             {
45                 for(int k = s[i-1][j]; k <= s[i][j+1]; k++)
46                 {
47                     int t = d[i-1][k] + (a[j] - a[k+1]) * (a[j] - a[k+1]);
48                     if(t < d[i][j])
49                     {
50                         d[i][j] = t;
51                         s[i][j] = k;
52                     }
53                 }
54             }
55         }
56 
57         printf("Case %d: %d\n", kase, d[m][n]);
58     }
59 
60     return 0;
61 }
代码君

 

posted @ 2015-08-01 13:24  AOQNRMGYXLMV  阅读(251)  评论(0编辑  收藏  举报