POJ 1180 Batch Scheduling(斜率优化DP)

【题目链接】 http://poj.org/problem?id=1180

【题目大意】

  N个任务排成一个序列在一台机器上等待完成(顺序不得改变),
  这N个任务被分成若干批,每批包含相邻的若干任务。
  从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。
  在每批任务开始前,机器需要启动时间S,
  而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。
  每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小

【题解】

  我们可以得到dp方程dp[i]=min{dp[j]+(sumT[i]-sumT[j]+S)*(sumF[n]-sumF[j])}
  dp[i]=(sumF[n]-sumF[j])*sumT[i]+dp[j]+(S-sumT[j])*(sumF[n]-sumF[j])
  是关于sumT[i]的一元一次方程,我们对此做斜率优化。

【代码】

#include <algorithm>
#include <cstdio>
#include <cstring>
typedef long long LL;
const int MAX_N=10010;
int n;
LL k,a[MAX_N],b[MAX_N],dp[MAX_N],S[MAX_N],F[MAX_N],deq[MAX_N];
LL f(int x,int y){return (F[n]-F[x])*S[y]+dp[x]+(k-S[x])*(F[n]-F[x]);}
bool check(int f1,int f2,int f3){
    LL a1=F[n]-F[f1],b1=dp[f1]+(k-S[f1])*(F[n]-F[f1]);
    LL a2=F[n]-F[f2],b2=dp[f2]+(k-S[f2])*(F[n]-F[f2]);
    LL a3=F[n]-F[f3],b3=dp[f3]+(k-S[f3])*(F[n]-F[f3]);
    return (a2-a1)*(b3-b2)>=(b2-b1)*(a3-a2);
}
void solve(){
    for(int i=0;i<n;i++)S[i+1]=S[i]+a[i],F[i+1]=F[i]+b[i];
    int s=0,t=1;
    deq[0]=0; dp[0]=0;
    for(int i=1;i<=n;i++){
        while(s+1<t&&f(deq[s],i)>=f(deq[s+1],i))s++;
        dp[i]=f(deq[s],i);
        while(s+1<t&&check(deq[t-2],deq[t-1],i))t--;
        deq[t++]=i;
    }printf("%lld
",dp[n]);
}
int main(){
    while(~scanf("%d%lld",&n,&k)){
        for(int i=0;i<n;i++)scanf("%lld%lld",&a[i],&b[i]);
        solve();
    }return 0;
}
原文地址:https://www.cnblogs.com/forever97/p/poj1180.html