关于斜率优化

文章目录

  • 正题……斜率优化
      • 1.0 简单的介绍
      • 1.1 斜率优化前言
      • 2.0 一些基础分析

这是一道经典的斜率优化

它就是任务安排……

首先可以看出他是一道 DP,然后就有了 O ( n 3 ) \text{O}(n^{3}) O(n3) 的优秀时间复杂度,在此就默认各位已经是基础 DP 高手,因此不做过多的讲解。

可是要切掉这道根本不需要斜率优化的水题,至少要考虑 O ( n 2 ) \text{O}(n^{2}) O(n2) 的算法。

这里需要用到费用提前处理思想

众所皆知:我们每分一组,后面未进行分组的一定会增加费用。

所以只需要提前将这些费用加上即可。

这样我们的 d p dp dp 数组也降了一维,定义 d p i dp_i dpi 表示完成前 i i i 个任务的最小费用,进而枚举上一次分组的最后任务 j j j 0 ≤ j < i 0 \le j < i 0j<i),即是 j + 1 ∼ i j+1 \sim i j+1i 属于同一分组,这一组等待时长 T T T 会对之后的分组都增加 T T T 的时间。

还需要预处理出一个 s u m t sumt sumt 数组,表示时间前缀和,一个 s u m c sumc sumc 数组,表示费用前缀和。

所以有了如下的状态转移方程:

f i = min ⁡ 0 ≤ j < i f j + ( s u m c i − s u m c j ) ∗ s u m t i + ( s u m c n − s u m c j ) ∗ s f_i=\min\limits_{0 \le j fi=0j<iminfj+(sumcisumcj)sumti+(sumcnsumcj)s

很明显,它的时间复杂度为 O ( n 2 ) \text{O}(n^{2}) O(n2),过洛谷那题轻轻松松,于是就有了一些恶臭版本,例如某人将 n n n 的范围开到了 1 0 5 10^{5} 105,本来 1 s 1s 1s 过了没什么障碍,可是他却将时限下调至 50 m s 50ms 50ms,怎么办呢?

@%#%&#&&&#&%%¥@¥*@……

正题……斜率优化

关于斜率优化,初次接触记忆犹新SDOI2016征途,很明显的一道 DP,于是年轻的我就开“征”了,结果后来看到标签大大四个字——斜率优化,当场蒙B,开始摆烂……

其实它的斜率优化真的很简单(如果你愿意花几十分钟去想一想……)。

在此引用某位大佬的题解,然后开始介绍那道被疯狂卡常的题目。


1.0 简单的介绍

首先,什么是斜率。

我们令它为 k k k,我们熟知一次函数表达式 y = k x + b y=kx+b y=kx+b,其中 k k k 就是斜率。

而对于斜率 k k k 的计算则更加简单。

我们假设有两点 P 1 ( x 1 , y 1 ) P_1(x1,y1) P1(x1,y1) P 2 ( x 2 , y 2 ) P_2(x2,y2) P2(x2,y2) 在该一次函数上,那么根据解析式可以列出方程:

x1*k+b=y1------------1式
x2*k+b=y2------------2式

1 1 1 式减去 2 2 2 式,则可以得到 ( x 1 − x 2 ) ∗ k = y 1 − y 2 (x1-x2)*k=y1-y2 (x1x2)k=y1y2,整理一下得到: k = y 1 − y 2 x 1 − x 2 k=\frac{y1-y2}{x1-x2} k=x1x2y1y2.

有了这些,我们可以进行之后的学习。

1.1 斜率优化前言

我们在之前的算法中运用到了以下状态转移方程:

f i = min ⁡ 0 ≤ j < i f j + ( s u m c i − s u m c j ) ∗ s u m t i + ( s u m c n − s u m c j ) ∗ s f_i=\min\limits_{0 \le j fi=0j<iminfj+(sumcisumcj)sumti+(sumcnsumcj)s.

我们去掉 min ⁡ \min min 并且拆开式子结合后可以得到:

f j = ( s u m t i + s ) ∗ s u m c j + ( f j − s u m t i ∗ s u m c i − s ∗ s u m c n ) ( o ≤ j < i ) f_j=(sumt_i+s)*sumc_j+(f_j-sumt_i*sumc_i-s*sumc_n)(o \le j fj=(sumti+s)sumcj+(fjsumtisumcissumcn)(oj<i)

我们对上面式子进行分析,发现变量只有 s u m c j sumc_j sumcj f j f_j fj 两者,剩下的全是常量,于是我们不禁联想上文提到的一次函数,其中 s u m t i + s sumt_i+s sumti+s 为斜率, f j − s u m t i ∗ s u m c i − s ∗ s u m c n f_j-sumt_i*sumc_i-s*sumc_n fjsumtisumcissumcn为截距(即为 b b b),这个转化非常重要!

2.0 一些基础分析

直线的斜率永远是一个固定的值,截距未知,所以当截距最小时, f j f_j fj 也取得最小值

首先按照横坐标递增维护一个单调队列,再把每个点画上去,可以得到以下两种情况。

关于斜率优化_第1张图片

关于斜率优化_第2张图片
未完待续……

你可能感兴趣的:(c++,编程,算法,动态规划,算法)