动态规划优化

来源:互联网 发布:java窗口按钮大小 编辑:程序博客网 时间:2024/05/18 00:04

单调队列

简述

函数 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;}
0 0
原创粉丝点击