poj 1180 Batch Scheduling 斜率优化dp

28 篇文章 0 订阅

poj 1180 Batch Scheduling 

http://poj.org/problem?id=1180

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


朴素状态转移方程:dp[i][j]=MIN(dp[i-1][k]+(S*i+T[j])*(c[j]-c[k]) ) 

可从后像前推,得dp[i]= MIN(dp[j] + (s + t[i]- t[j])) *f[i]; ( i< j<= n+ 1)


贴个博客http://blog.csdn.net/ascii991/article/details/7545261像大牛学习~~

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn= 10005;
long long dp[maxn];
int n, s, t[maxn], f[maxn], q[maxn];
void dynamic(){
    int i, j, k, head, tail;
    tail= 0;head= 0;
    dp[n+1]= f[n+1]= t[n+1]= 0;
    q[tail++]= n+1;
   /*状态转移方程: dp[i]= MIN(dp[j] + (s + t[i]- t[j])) *f[i]; ( i< j<= n+ 1)
   i <j <k时:(dp[j]- dp[k])/(t[j]- t[k]) >= f[i] 为 k不差于j的条件
   g[j, k] >= f[i] k不差于j的条件
   g[j, k] < f[i] j 优于 k
   
   对于队首元素a > b,若g[b, a] <= f[i],则b不差于a
   且f随i递减而递增,故对于以后的f[p],g[b, a]必定小于f[p],所以head++
   
   对于队尾元素,a>b, 新加的i<b,即 a>b>i
   若 g[i, b]< g[b, a] 时,b永远不会被选到
   证明:g[i, b] >= f[i] ,i为不差于b
         f[i]> g[b, a] > g[i, b]时,b优于a,但i优于b,故不选b
         
   */
    for( i= n; i>= 1; i--){
        while( tail - head >= 2 && (dp[q[head+1]] - dp[q[head]]) 
              <= ( t[q[head+1]] - t[q[head]])*f[i])
            head++;
        dp[i]= dp[q[head]] + (s+ t[i] - t[q[head]])* f[i];
        while( tail - head >= 2 && (dp[i] - dp[q[tail-1]])*(t[q[tail-1]] - t[q[tail-2]]) < (dp[q[tail-1]] - dp[q[tail-2]])*(t[i]- t[q[tail-1]]))
            tail--;
        q[tail++]= i;
    }
    printf("%I64d\n",dp[1]);
}
int main(){
   // freopen("1.txt", "r", stdin);
    int i, j, aa, bb;
    while( scanf("%d%d", &n, &s)!= EOF){
        t[0]= f[0]= 0;
        for( i= 1; i<= n; i++){
            scanf("%d%d", &aa, &bb);
            t[i]= aa;
            f[i]= bb;
        }
        t[n+1]= 0;
        f[n+1]= 0;
        for( i= n; i>= 1; i--){
            t[i]+= t[i+1];
            f[i]+= f[i+1];
        }
        dynamic();
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值