第五章 动态规划 (10):斜率优化DP

本文介绍了动态规划在任务安排问题中的应用,通过斜率优化减少计算复杂度。讨论了任务安排I和II,利用斜率优化减少计算量,维护凸包下边界。此外,还探讨了运输小猫问题,将其转化为求解最小花费的动态规划问题,利用单调性优化算法。
摘要由CSDN通过智能技术生成

1、任务安排 I

ACwing 300

由于每次的启动消耗的时间会对后面的所有任务都产生影响,所以在进行当前组任务时先将启动产生的影响累加到当前组别中,方便于计算后面的状态。

集合
f [ i ] f[i] f[i]:表示将前 i i i 个任务分批执行的最小费用

集合划分
i i i 结尾的该批次任务的开头进行划分。上面一个批次结尾为 j ∈ [ 0 , i − 1 ] j \in[0,i-1] j[0,i1],从 j + 1   i j+1~i j+1 i 是最后一批次,那么从 j + 1 j + 1 j+1 i i i 这一批次的消耗 = 到 i i i 的总时间 x 从 j j j i i i 的 费用之和 + 最后一批任务启动时间对当前任务及后续任务整体的影响。即 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 ] ) Sumt[i] \times (Sumc[i] - Sumc[j]) + S * (Sumc[n] - Sumc[j]) Sumt[i]×(Sumc[i]Sumc[j])+S(Sumc[n]Sumc[j])最终的状态转移方程为: f ( i ) = m i n ( f ( 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(f(i), f(j)+Sumt[i] \times (Sumc[i] - Sumc[j]) + S * (Sumc[n]-Sumc[j])) f(i)=min(f(i),f(j)+Sumt[i]×(Sumc[i]Sumc[j])+S(Sumc[n]Sumc[j]))
在这里插入图片描述

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 5010;

int n, s;
int sc[N], st[N];
LL f[N];

int main() {
   
    scanf("%d%d", &n, &s);
    for (int i = 1; i <= n; i++) {
   
        scanf("%d%d", &st[i], &sc[i]);
        st[i] += st[i - 1];
        sc[i] += sc[i - 1];
    }

    memset(f, 0x3f, sizeof f);
    f[0] = 0; // 处理前0个任务的花费 = 0

    for (int i = 1; i <= n; i++)
        for (int j = 0; j < i; j++)
            f[i] = min(f[i], f[j] + (sc[i] - sc[j]) * (LL) st[i] + (LL) s * (sc[n] - sc[j]));

    printf("%lld\n", f[n]);

    return 0;
}

2、任务安排 II(凸包优化)

ACwing 301

由上一题的公式可得如下推导(这里暂时不考虑 m i n min min):
f ( 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 ( j ) − ( S + S u m t [ i ] ) × S u m c [ j ] + S u m t [ i ] × S u m c [ i ] + S × S u m c [ n ] \begin{aligned} f(i)&=f(j)+Sumt[i] \times (Sumc[i] - Sumc[j]) + S \times (Sumc[n]-Sumc[j])\\ &= f(j)-(S+ Sumt[i]) \times Sumc[j]+ Sumt[i] \times Sumc[i] + S \times Sumc[n]\\ \end{aligned} f(i)=f(j)+Sumt[i]×(Sumc[i]Sumc[j])+S×(Sumc[n]Sumc[j])=f(j)(S+Sumt[i])×Sumc[j]+Sumt[i]×Sumc[i]+S×Sumc[n]经过进一步变形有
f ( j ) = ( S u m t [ i ] + S ) × S u m c [ j ] + f ( i ) − S u m t [ i ] × S u m c [ i ] − S × S u m c [ n ] f(j)=(Sumt[i]+S) \times Sumc[j]+f(i)-Sumt[i] \times Sumc[i] - S \times Sumc[n] f(j)=(Sumt[i]+S)×Sumc[j]+f(i)Sumt[i]×Sumc[i]S×Sumc[n]这里我们令
y = f ( j ) k = S u m t [ i ] + S x = S u m c [ j ] b = f ( i ) − S u m t [ i ] × S u m c [ i ] − S × S u m c [ n ] \begin{aligned} y &= f(j)\\ k &= Sumt[i] + S\\ x &= Sumc[j]\\ b &= f(i)-Sumt[i] \times Sumc[i] - S \times Sumc[n] \end{aligned} ykxb=f(j)=Sumt[i]+S=Sumc[j]=f(i)Sumt[i]×Sumc[i]S×Sumc[n]因此整个式子可以表示成 y = k x + b y = kx+b y=kx+b又因为 j ∈ [ 0 ,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值