动态规划优化

这篇博客介绍了动态规划中的单调队列优化方法,用于处理函数f[i]=min(g[j])的转移,并详细阐述了四边形不等式及其在优化dp过程中的应用。通过举例说明如何利用四边形不等式解决最小代价子母树问题,实现决策函数g[i][j]的优化,从而提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单调队列

简述

函数 f[i],转移如下:
f[i]=min(g[j]) 其中 g[j] 是关于 jf[j] 的一个函数,且 b[i]j<i
维护一个单调递增的队列,队列中的元素下表保证关于 i 合法,即 b[i]j<i。每次决策前删除队首不合法的元素,决策时取队首元素转移,决策后将当前值加入队尾并保证单调性即可。复杂度为 O(n)

四边形不等式

简述

函数 f[i][j] ,转移如下:
f[i][j]=min(f[i][k]+f[k+1][j]+w[i][j]) 其中 ik<j
若函数 w[i][j] 具有以下两种性质:
1、当 ab<cdw[b][c]w[a][d]
2、当 ab<cdw[a][c]+w[b][d]w[b][c]+w[a][b]
我们称函数 w[i][j] 满足关于区间包含的单调性与四边形不等式,此时函数 f[i][j] 也将满足四边形不等式,其决策函数 g[i][j] 将满足关于区间包含的单调性。我们可以利用 g[i][j] 满足关于区间包含的单调性这一性质来缩小决策变量 k 的枚举范围,以优化dp。

一些题目

最小代价子母树

Description

设有 n 堆沙子,每堆沙子都有一定的质量,现在要将 n 堆沙子归并成一堆,归并的过程为每次将相邻的两堆沙子合成一堆,这样经过 n1 次归并后将只剩下一堆沙子。两堆沙子的质量的和为归并两堆沙子的代价,现求进行 n1 次归并的最小代价。

Solution & Code

f[i][j]=min(f[i][k]+f[k+1][j]+sum[i][j])
其中 sum[i][j] 满足关于区间包含的单调性与四边形不等式,故 f[i][j] 满足四边形不等式,其决策函数 g[i][j] 满足关于区间包含的单调性,所以可以用四边形不等式加速。

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 105;
const int inf = 1e9;

int n, w[maxn], s[maxn], f[maxn][maxn], g[maxn][maxn];

int main(){

    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);
    for(int i = 1; i <= n; ++i) s[i] = s[i-1] + w[i];
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j)
            f[i][j] = inf;
    for(int i = 1; i <= n; ++i) f[i][i] = 0, g[i][i] = i;
    for(int l = 2; l <= n; ++l)
        for(int i = 1, j = i + l - 1; j <= n; ++i, ++j)
            for(int k = g[i][j-1]; k <= g[i+1][j] && k < j; ++k){
                int tmp = f[i][k] + f[k+1][j] + s[j] - s[i-1];
                if(f[i][j] > tmp){
                    f[i][j] = tmp;
                    g[i][j] = k;
                }
            }
    printf("%d\n", f[1][n]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值