POJ 1180 Batch Scheduling 斜率DP
总共有 个任务,编号为 ,将这 个任务分成任意多个 batch ,每个 batch 中包含连续编号的任务,按照 batch 中最小编号的顺序进行依次处理每一批,起始时刻是 ,每个 batch 的准备时间是 ,第 个任务的处理时间为 ,系数为 ,同一个 batch 里的所有任务在同一时刻输出,也就是说,在某一个 batch 中,假如他们的起始时间是 ,包含任务的编号是 ,则他们的输出时间均是 ,最终的总花费是 第 个任务的输出时间乘上系数 后求和,求最小总花费。
考虑斜率优化。用 来表示 的最小花费,则有:
其中 为处理时间 的后缀和, 为系数 的后缀和。令 且 优于 ,则有:
令 ,并且对于 ,可以证明若 ,则 必定不是最优点,可舍去,证明如下:
首先,假如 ,则 ,因此 比 优;
然后,假如 ,则 比 优。
代码如下:
#include<iostream>
#include<cstdio>
//#define WINE
#define MAXN 10100
using namespace std;
int n,S,T[MAXN],f[MAXN],st[MAXN],sf[MAXN],q[MAXN],h,t,dp[MAXN];
int up(int j,int k){
return dp[j]-dp[k];
}
int down(int j,int k){
return st[j]-st[k];
}
int getDP(int k,int i){
return dp[k]+(S+st[i]-st[k])*sf[i];
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
while(scanf("%d",&n)!=EOF){
scanf("%d",&S);
for(int i=1;i<=n;i++)scanf("%d%d",&T[i],&f[i]);
st[n+1]=sf[n+1]=0;
for(int i=n;i>=1;i--){
st[i]=st[i+1]+T[i];
sf[i]=sf[i+1]+f[i];
}
h=t=0;q[t++]=n+1;
for(int i=n;i>=1;i--){
while(h+1<t&&up(q[h+1],q[h])<sf[i]*down(q[h+1],q[h]))
h++;
dp[i]=getDP(q[h],i);
while(h+1<t&&up(i,q[t-1])*down(q[t-1],q[t-2])<up(q[t-1],q[t-2])*down(i,q[t-1]))
t--;
q[t++]=i;
}
printf("%d\n",dp[1]);
}
return 0;
}