码迷,mamicode.com
首页 > 其他好文 > 详细

斜率优化dp小结

时间:2016-05-12 15:13:29      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

单调队列优化

在写斜率优化之前,我们来回顾一下单调队列优化的dp
1. 对于如下形式的dp方程

dp[i]=min{dp[j]+f(j)}(0<j<i)

我们直接用一个变量维护(0, i)中dp[j] + f(j)的最小值即可

2.对于如下形式的dp方程

dp[i]=min{dp[j]+f(j)}(i?m<j<i)

我们可以用一个单调队列维护一个(i - m, j)中dp[j] + f(j)的最小值,然后做到O(1)转移。

斜率优化

基本形式

但是对于形如

dp[i]=min{dp[j]+f(i,j)}

的方程,无法做到O(1)计算dp[j]+f(i,j)的最小值,这时就需要斜率优化这个技巧来解决这个问题了。
令k < j < i,当我们更新dp[i]时,如果有dp[j] + f(i, j) 比dp[k] + f(i, k)更优,则有dp[j] + f(i, j) - (dp[k] + f(i, k) < 0,对于这个不等式如果能够化解成如下形式
Y(j)?Y(k)X(j)?X(k)<f(i)

我们就能通过斜率优化这个dp了。
让我们来举一个例子: hdu3507 dp方程为
dp[i]=min{dp[j]+M+(sum[i]?sum[j])2(0<j<i)}

令k < j < i,当有
dp[j]+M+(sum[i]?sum[j])2?(dp[k]+M+(sum[i]?sum[k])2)<0

从j转移到i, 比从k转移到i更优,变换此不等式可得:
(dp[j]+sum[j]2)?(dp[k]+sum[k]2)sum[j]?sum[k]<2sum[i]

Y(i)=dp[i]+sum[i]2, X(i)=sum[i], f(i)=2sum[i]则将此不等式化解为上述形式。

优化方法:

可以发现,若满足Y(j)?Y(k)X(j)?X(j)<f(i)则j转移到i,比k转移到i更优,如果我们把(X(j), Y(j)), (X(k), Y(k))当成平面上的两个点Pj, Pk,这个不等式的含义即为若PjPk???的斜率<f(i)则,从j转移更优。
令grad(i, j)表示PiPj???的斜率,现在我们假设grad(i,j) < grad(j, k),若grad(i, j) < f(I),则i比j更优,若grad(i, j) > f(I), 则grad(j, k) > f(I),那么从k转移比从j转移更优,当grad(i, j) < grad(j, k)的时候,无论如何j转移到i都不会是最优。而这种情况恰好对应下图
技术分享
所以这种情况时,我们可以直接把j点删除,最后能够转移的点集只会存在这种图形,技术分享
所以最后我们维护一个上凸集即可。
但是此时我们还是没有解决最终问题,如何才能找到转移到i点的最优的点呢。可以发现最后的点集一定是一个凸集,也就是斜率单调!!这样对于k < j, grad(j,k) < f(i),时更优,从图形特点我们可以发现如果j比k优,那么j点比所有比k小的点都优,所以对于每一个f(i),我们维护一个所有比i点小的凸集,二分查找斜率比f(i)小的编号最大的点,就是最优的转移点。如果f(i)也满足单调性,比如这道题,我们还可以直接维护一个单调队列就能解决这个问题。

分治做法

对于f(i)单调的这种情况,除了使用单调队列优化的斜率优化做,我们还有另外一种分治的做法,但是复杂度会变成O(nlogn) 比O(n)差。
当f(i)单调的时候,我们可以发现若a > b,则f(a) > f(b),设转移到a的最优点是c,转移到b的最优点是d,一定有c > d。也就是转移到a的最优点一定大于等于转移到b的最优点。考虑这样的分治

void dfs(int l, int r, int dl, int dr) {
    //[l,r]表示现在更新[l,r]区间dp[i]的最优值
    //用j -> f(i),表示j是更新f(i)最优值的最优点
    //那么[dl,dr]表示更新dp([l,r])的点,一定在[dl,dr]范围内
    int mid = (l + r) >> 1; 
    int dm = dl;
    int g = inf;
    for (int i = dl; i <= dr; i++) {
        if(g < dp[i] + f(i, mid)) {
            g = dp[i] + f(i, mid);//记录更新dp[mid]的最优
            dm = i;//记录更新dp[mid]的最优点
        }
    }
    dp[mid] = g; //更新dp[mid]的值
    //因为上文叙述的单调性,
    //更新[l,mid-1]的最优点,一定在[dl,dm]范围内
    if(l < mid) dfs(l, mid - 1, dl, dm);
    //更新[mid+1,r]的最优点,一定在[dm,dr]范围内
    if(mid < r) dfs(mid + 1, r, dm, dr);
}

可以发现这个分治比起斜率优化,不仅写起来方便很多,并且适用的范围也更广。这个做法不局限于斜率单调,可以发现只要满足c是更新f(a)的最优点,d是更新f(b)的最优点,若a > b 一定有 c > d,则可以有这个分治做。

PS:

这个做法是我在codeforces 674E,跟Claris神犇的代码学会的solution,在此特地感谢Claris.这个做法着实是非常的劲啊!多一个log,但是换来编码复杂度和通用性更广的解法。

斜率优化dp小结

标签:

原文地址:http://blog.csdn.net/lxc779760807/article/details/51366552

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!