【进阶】斜率优化,帮你摆脱DP超时的烦恼

如果想了解更多内容,欢迎关注我的微信公众号:信息学竞赛从入门到巅峰。

 

戳这里获得更好的阅读体验哦。

 

经过了前几期的介绍,相信大家对主要的DP类型都有了一定的了解。但是你是否感受过好不容易想出了动规方程,但是却因时间复杂度过高而无法A题的烦恼呢?

今天,我来介绍一种动态规划的优化方法——斜率优化。

 

例题

(例题来源洛谷,侵删)

 

一个想法

看到这道题,我们很容易就能想到一个O(N^2)的算法。

我们定义F[i]表示完成前i件物品的最少花费,转移方程显然:

由于我们没有记录一共分了几段,所以对机器启动时间所造成的花费比较难以计算。这里,我们把费用提前,就是在i位置启动一次机器,i~n所有物品的完成时刻都要推迟s。所以,直接把这些花费加上去就行了。

这个算法的时间复杂度是O(N^2)的,可以通过这道题目。但是,如果N在大一点,到1e5,甚至1e6,该怎么办呢?

 

一个优化

这时候,就需要我们的斜率优化登场啦。

 

Code


#include <bits/stdc++.h>
using namespace std;

const int N = 5005;
int f[N], t[N], sf[N], st[N];
int n, s, F[N], que[N], l, r;

double calc(int i, int j) {
    return (F[i] - F[j]) / (sf[i] - sf[j]);
}

int main () {
    scanf ("%d%d", &n, &s);
    for (int i = 1; i <= n; ++i) {
        scanf ("%d%d", &t[i], &f[i]);
        sf[i] = sf[i - 1] + f[i];
        st[i] = st[i - 1] + t[i];
    }
    que[l = r = 1] = 0;
    for (int i = 1; i <= n; ++i) {
        while (l < r && calc(que[l], que[l + 1]) < st[i] + s) l++;
        F[i] = F[que[l]] + s * (sf[n] - sf[que[l]]) + st[i] * (sf[i] - sf[que[l]]);
        while (l < r && calc(que[r - 1], que[r]) > calc(que[r], i)) r--;
        que[++r] = i;
    }
    printf ("%d\n", F[n]);
    return 0;
}

 

总结

斜率优化DP,有一个很明显的特征:每一个决策点可以用一个坐标来表示,决策之间的关系和坐标之间的斜率有关。通过单调队列,我们可以把DP的时间复杂度降一个维度,大大提高算法的效率。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值