cychester

POJ1180 Batch Scheduling -斜率优化DP

题解

  将费用提前计算可以得到状态转移方程: $F_i = \min(F_j + sumT_i * (sumC_i - sumC_j) + S \times (sumC_N - sumC_j)$

  把方程进行分离, 得到 $S\times sumC_j  + F_j = sumT_i \times sumC_j + F_i - S \times sumC_N$。

   将等号左边看成纵坐标, $sumC_j$看成横坐标, $sumT_i$为斜率来进行斜率优化。

  由于 $sumT_i$是递增的, 即斜率是递增的, 维护一个单调队列, 第一个斜率大于$sumT_i$的端点就为决策点

  斜率优化dp还是很套路的

代码

  

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rd read()
 5 #define rep(i,a,b) for( int i = (a); i <= (b); ++i )
 6 #define per(i,a,b) for( int i = (a); i >= (b); --i )
 7 using namespace std;
 8 
 9 const int N = 1e4 + 1e3;
10 
11 int n, m, sumT[N], sumC[N], S, f[N], q[N];
12 
13 int cross(int a, int b, int c) { //点积
14     int ax = sumC[a], bx = sumC[b], cx = sumC[c];
15     int ay = f[a], by = f[b], cy = f[c];
16     int x = bx - ax, xx = cx - ax, y = by - ay, yy = cy - ay;
17     return x * yy - xx * y;
18 }// 向量ab, ac
19 
20 double calk(int a, int b) {
21     int ax = sumC[a], bx = sumC[b], ay = f[a], by = f[b];
22     return 1.0 * (by - ay) / (bx - ax);
23 }
24 
25 int read() {
26     int X = 0, p = 1;char c = getchar();
27     for(; c > '9' || c < '0'; c = getchar() ) if( c == '-' ) p = -1;
28     for(; c >= '0' && c <= '9'; c = getchar() ) X = X * 10 + c - '0';
29     return X * p;
30 }
31 
32 int main()
33 {
34     n = rd; S = rd;
35     rep(i, 1, n) {
36         int t = rd, c = rd;
37         sumT[i] = sumT[i - 1] + t;
38         sumC[i] = sumC[i - 1] + c;
39     }
40     memset(f, 0x3f, sizeof(f));
41     int l = 1, r = 1;
42     q[1] = f[0] = 0;
43     rep(i, 1, n) {
44         while(l < r && calk(q[l], q[l + 1]) <= S + sumT[i]) l++;
45         if(l <= r) f[i] = f[q[l]] + sumT[i] * (sumC[i] - sumC[q[l]]) + S * (sumC[n] - sumC[q[l]]);
46         while(l < r && cross(q[r - 1], q[r], i) <= 0) r--;
47         q[++r] = i;
48     }
49     printf("%d\n",f[n]);
50 }
View Code

 

posted on 2018-08-19 18:44  cychester  阅读(237)  评论(0编辑  收藏  举报

导航