斜率优化dp (P2365/P5785 任务安排)

P2365 任务安排

  这道题因为数据量不大,不需要用到斜率优化dp也能过(解法三用了斜率优化dp),但后续的 P5785 虽然题意不变,但数据范围变大了,需要用到斜率优化dp来解决,所以就先用较简单的做法介绍一下这道题。
  洛谷:P2365 任务安排
题目描述:
  有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻0开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。
  另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci。
  请为机器规划一个分组方案,使得总费用最小。
输入格式:
  第一行包含整数 N。
  第二行包含整数 S。
  接下来N行每行有一对整数,分别为 Ti 和 Ci,表示第 i 个任务单独完成所需的时间 Ti 及其费用系数 Ci。
输出格式:
  输出一个整数,表示最小总费用。
数据范围:
  1 ≤ N ≤ 5000
  0 ≤ S ≤ 50
  1 ≤ Ti,Ci ≤ 100

解法一 O(N^3):

  求出T,C的前缀和sumT,sumC。即: s u m T [ i ] = ∑ j = 1 i T [ j ] sumT[i] = \sum_{j=1}^{i}T[j] sumT[i]=j=1iT[j] s u m C [ i ] = ∑ j = 1 i C [ j ] sumC[i] = \sum_{j = 1} ^ {i}C[j] sumC[i]=j=1iC[j]
  设F[i, j]表示把前i个任务分成 j 批执行的最小费用,则第 j 批任务完成的时间就是j * s + sumT[i]。以第j - 1批和第j批任务的分界点为DP的“决策”,状态转移方程为:
F [ i , j ] = min ⁡ 0 ≤ k < j { F [ k , j − 1 ] + ( s ∗ j + s u m T [ i ] ) ∗ ( s u m C [ i ] − s u m C [ k ] } F[i, j] = \min_{0{\leq}k<j} \{F[k, j - 1] + (s * j + sumT[i]) * (sumC[i] - sumC[k]\} F[i,j]=0k<jmin{ F[k,j1]+(sj+sumT[i])(sumC[i]sumC[k]}
  该解法的时间复杂度为O(N3)。

解法二:O(N^2):

  本题并没有规定需要把任务分成多少批,在上一个解法中之所以需要批数 j , 是因为我们需要知道机器启动了多少次(每次启动都要S单位时间),从而计算出 i 所在的一批任务的完成时刻。
  事实上,在执行一批任务时,我们不容易直接得知在此之前机器启动过几次。但我们知道,机器因执行这批任务而花费的启动时间S,会累加到在此之后所有任务的完成时刻上。设 F[i] 表示把前 i 个任务分成若干批执行的最小费用,状态转移方程为:
   F [ i ] = min ⁡ 0 ≤ j < i { F [ j ] + s u m T [ i ] ∗ ( s u m C [ i ] − s u m C [ j ] ) + s ∗ ( s u m C [ N ] − s u m C [ j ] ) } F[i] = \min_{0{\leq}j<i} \{F[j] + sumT[i] * (sumC[i] - sumC[j]) + s * (sumC[N] - sumC[j])\} F[i]=0j<imin{ F[j]+sumT[i](sumC[i]sumC[j])+s(sumC[N]sumC[j])}
  在上式中,第 j + 1 ~ i个任务在同一批内完成,sumT[i] 是忽略机器的启动时间
时,这批任务的完成时刻。因为这批任务的执行,机器的启动时间S会对第j + 1个之后的所有任务产生影响,故我们把这部分补充到费用中。
  也就是说,我们没有直接求出每批任务的完成时刻,而是在一批任务“开始”对后续任务产生影响时,就先把费用累加到答案中。这是一种名为“费用提前计算”的经典思想。
  该解法的时间复杂度为0 (N2) 。

代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int read(){
   
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -
  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值