• 四边形不等式优化


    四边形不等式优化条件(转自这里

    在动态规划中,经常遇到形如下式的转台转移方程:

    m(i,j)=min{m(i,k-1),m(k,j)}+w(i,j)(i≤k≤j)(min也可以改为max)

    上述的m(i,j)表示区间[i,j]上的某个最优值。w(i,j)表示在转移时需要额外付出的代价。该方程的时间复杂度为O(N^3)。


    下面我们通过四边形不等式来优化上述方程,首先介绍什么是”区间包含的单调性“和”四边形不等式“

    (1)区间包含的单调性:如果对于i≤i'<j≤j',有w(i',j)≤w(i,j'),那么说明w具有区间包含的单调性。(可以形象理解为如果小区间包含于大区间中,那么小区间的w值不超过大区间的w值)

    (2)四边形不等式:如果对于i≤i'<j≤j',有w(i,j)+w(i',j')≤w(i',j)+w(i,j'),我们称函数w满足四边形不等式。(可以形象理解为两个交错区间的w的和不超过小区间与大区间的w的和)

    下面给出两个定理

    定理一:如果上述的w函数同时满足区间包含单调性和四边形不等式性质,那么函数m也满足四边形不等式性质。


    我们再定义s(i,j)表示m(i,j)取得最优值时对应的下标(即i≤k≤j时,k处的w值最大,则s(i,j)=k)。此时有如下定理

    定理二:假如m(i,j)满足四边形不等式,那么s(i,j)单调,即s(i,j)≤s(i,j+1)≤s(i+1,j+1)。


    好了,有了上述的两个定理后,我们发现如果w函数满足区间包含单调性和四边形不等式性质,那么有s(i,j-1)≤s(i,j)≤s(i+1,j)。即原来的状态转移方程可以改写为下式:

    m(i,j)=min{m(i,k-1),m(k,j)}+w(i,j)(s(i,j-1)≤k≤s(i+1,j))(min也可以改为max)

    由于这个状态转移方程枚举的是区间长度L=j-i,而s(i,j-1)和s(i+1,j)的长度为L-1,是之间已经计算过的,可以直接调用。不仅如此,区间的长度最多有n个,对于固定的长度L,不同的状态也有n个,故时间复杂度为O(N^2),而原来的时间复杂度为O(N^3),实现了优化!今后只需要根据方程的形式以及w函数是否满足两条性质即可考虑使用四边形不等式来优化了。

    以51nod 1022为例子。

    N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。
     
    例如: 1 2 3 4,有不少合并方法
    1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
    1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
    1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)
     
    括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
    Input
    第1行:N(2 <= N <= 1000)
    第2 - N + 1:N堆石子的数量(1 <= A[i] <= 10000)
    Output
    输出最小合并代价
    Input示例
    4
    1
    2
    3
    4
    Output示例
    19

    (注意,这题是环,不是线)
     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define ll long long
     5 using namespace std;
     6 const int MAX = 2005;
     7 const int INF = 0x3f3f3f3f;
     8 int dp[MAX][MAX], sum[MAX][MAX], s[MAX][MAX], a[MAX];
     9 
    10 int main() {
    11     int n;
    12     scanf("%d",&n);
    13     for(int i = 1; i <= n; i ++) {
    14         scanf("%d",&a[i]);
    15         a[i+n] = a[i];
    16     }
    17     for(int i = 1; i <= 2*n; i ++) {
    18         dp[i][i] = 0;
    19         s[i][i] = i;
    20     }
    21     for(int i = 1; i <= 2*n; i ++) {
    22         for(int j = i; j <= i+n; j ++) {
    23             sum[i][j] = sum[i][j-1]+a[j];
    24         }
    25     }
    26     for(int len = 2; len <= n; len ++) {
    27         for(int i = 1; i <= 2*n-len+1; i ++) {
    28             int j = i+len-1;
    29             dp[i][j] = INF;
    30             for(int k = s[i][j-1]; k <= s[i+1][j]; k ++){
    31                 if(dp[i][j] > dp[i][k] + dp[k+1][j] + sum[i][j]){
    32                     dp[i][j] = dp[i][k] + dp[k+1][j] + sum[i][j];
    33                     s[i][j] = k;
    34                 }
    35             }
    36         }
    37     }
    38     int ans = INF;
    39     for(int i = 1; i < n; i ++) {
    40         ans = min(ans,dp[i][i+n-1]);
    41     }
    42     printf("%d
    ",ans);
    43     return 0;
    44 }
  • 相关阅读:
    SQL语句大全
    SQL SERVER 用sql语句将一列数据拼接成一个字符串
    常用 SQl 语句大全
    巧用一条SQL语句实现其它进制到十进制转换
    sql 2005
    sql convert(varchar(10),getdate(),120)
    sqlserver 日期函数
    转:DBCC CHECKDB 数据库或表修复
    Linux下使用SFTP命令
    mySQL 教程 第7章 存储过程和函数
  • 原文地址:https://www.cnblogs.com/xingkongyihao/p/7241987.html
Copyright © 2020-2023  润新知