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

    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(N3)

  

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

    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的和)

  下面给出两个定理:

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

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

    2、假如 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 函数是否满足两条性质即可考虑使用四边形不等式来优化了。

  以上描述状态用 m(i,j),后文用的 dp[i][j],所代表含意是相同的,特此说明。

  以石子合并问题为例。

  例如有6堆石子,每堆石子数依次为3 4 6 5 4 2

  因为是相邻石子合并,所以不能用贪心(每次取最小的两堆合并),只能用动归。(注意:环形石子的话,必须要考虑最后一堆和第一堆的合并。)

  例如:一个合并石子的方案:

    第一次合并 3 4 6 5 4 2 ->7

    第二次合并 7 6 5 4 2 ->13

    第三次合并 13 5 4 2 ->6

    第四次合并 13 5 6 ->11

    第五次合并 13 11 ->24

  总得分=7+6+11+13+24=61 显然,比贪心法得出的合并方案(得分:62)更优。

  

  动归分析类似矩阵连乘等问题,得出递推方程:

    设 dp[i][j] 表示第 i 到第 j 堆石子合并的最优值,sum[i][j] 表示第 i 到第 j 堆石子的总数量。

    (可以在计算开始先做一遍求所有的 sum[i],表示求出所有第1堆到第i堆的总数量。则 sum[i][j]=sum[j]-sum[i]。这样计算比较快。)

  那么就有状态转移公式:

      

    这里 i<=k<j

  普通解法需要 O(n^3)。下面使用四边形不等式进行优化。

  首先判断是否符合区间单调性和四边形不等式。

     i  i'    j    j'

    3 4 6 5 4 2

  单调性:

    w[i',j] = 4+6+5=15 w[i,j'] =3+4+6+5+4+2=24

  故w[i',j] <= w[i,j'] 满足单调性

  四边形不等式:

    w[i,j] + w[i',j'] = (3+4+6+5) + (4+6+5+4+2) = 18+21 = 39

    w[i',j] + w[i,j'] = (4+6+5) + (3+4+6+5+4+2) = 15 + 24 = 39

    故 w[i,j] + w[i',j'] <= w[i',j] + w[i,j']

  故石子合并可利用四边形不等式进行优化。

  利用四边形不等式,将原递推方程的状态转移数量进行压缩(即缩小了k的取值范围)。

  令 s[i][j]=min{k | dp[i][j] = dp[i][k-1] + dp[k][j] + w[i][j]},即计算出 dp[i][j] 时的最优的 k 值(本例中寻优为取最小)

  也可以称为最优决策时的 k 值。由于决策 s 具有单调性,因此状态转移方程中的 k 的取值范围可修改为 :

    s[i,j-1] <= s[i,j] <= s[i+1,j]

    边界:s[i,i] = i

  因为 s[i,j] 的值在 m[i,j] 取得最优值时,保存和更新,因此 s[i,j-1] 和 s[i+1,j] 都在计算 dp[i][j-1] 以及 dp[i+1][j] 的时候已经计算出来了。

  因此,s[i][j] 即 k 的取值范围很容易确定。

  根据改进后的状态方程,以及 s[i][j] 的定义方程,可以很快的计算出所有状态的值。计算过程可以如下表所示(类似于矩阵连乘的打表)。

  状态表(如果是环形石子合并,需要打2n*2n的表)

    3 4 6 5 4 2

  

  例如:

    计算dp[1][3],由于s[1][2]=1,s[2][3]=2,则k值的取值范围是1<=k<=2

    则,dp[1][3]=min{dp(1,1)+dp(2,3)+13, dp(1,2)+dp(3,3)+13}=min{10+13, 7+13}=20,将其填到状态表。同时,由于取最优值的k等于2,则将其填到s表。

    同理,可以计算其他状态表和s表中的值。

      dp[2][4]=min{dp(2,2)+dp(3,4)+15, dp(2,3)+dp(4,4)+15}=min{11+15, 10+15}=25

      k=3

    从表中可以看出,当计算dp[2][5]的时候,由于s[ i,j-1]=s[ 2,4]=3,s[ i+1,j]=s[3,5]=3,此时k的取值范围已经限定为只有一个,大幅缩短了寻找最优解的时间。

  这里给出程序代码:

 #include<iostream>
#include<cstdio>
using namespace std; const int N=;
const int INF=0x7fffffff;
int n;
int a[N],sum[N],dp[N][N],s[N][N];
void f();
int main()
{
while(~scanf("%d",&n))
{
sum[]=;
for (int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-]+a[i];
}
f();
printf("%d\n",dp[][n]);
}
return ; }
void f()
{
for (int i=;i<=n;i++) dp[i][i]=,s[i][i]=i;
for (int r=;r<n;r++)
{
for (int i=;i<n;i++)
{
int j=i+r;
if(j>n) break;
dp[i][j]=INF;
for (int k=s[i][j-];k<=s[i+][j];k++)
{
if(dp[i][j]>dp[i][k]+dp[k+][j])
{
dp[i][j]=dp[i][k]+dp[k+][j];
s[i][j]=k;
}
}
dp[i][j]+=sum[j]-sum[i-];
}
}
}

本文转载自网易博客:

    http://blog.163.com/dqx_wl/blog/static/2396821452015111133052112/

四边形不等式优化_石子合并问题_C++的更多相关文章

  1. 四边形不等式优化DP——石子合并问题 学习笔记

    好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的 ...

  2. <四边形不等式优化>[NOI1995]石子合并

    留个坑 挺套路的 明天来写个总结 #include<cstdio> #include<algorithm> inline int read() { int x = 0,f = ...

  3. 区间DP石子合并问题 & 四边形不等式优化

    入门区间DP,第一个问题就是线性的规模小的石子合并问题 dp数组的含义是第i堆到第j堆进行合并的最优值 就是说dp[i][j]可以由dp[i][k]和dp[k+1][j]转移过来 状态转移方程 dp[ ...

  4. 【无聊放个模板系列】HDU 3506 (四边形不等式优化DP-经典石子合并问题[环形])

    #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #inc ...

  5. [NOI1995]石子合并 四边形不等式优化

    链接 https://www.luogu.org/problemnew/show/P1880 思路 总之就是很牛逼的四边形不等式优化 复杂度\(O(n^2)\) 代码 #include <ios ...

  6. 51nod 1022 石子归并 V2 —— DP四边形不等式优化

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1022 1022 石子归并 V2  基准时间限制:1 秒 空间限 ...

  7. codevs3002石子归并3(四边形不等式优化dp)

    3002 石子归并 3 参考 http://it.dgzx.net/drkt/oszt/zltk/yxlw/dongtai3.htm  时间限制: 1 s  空间限制: 256000 KB  题目等级 ...

  8. Codevs 3002 石子归并 3(DP四边形不等式优化)

    3002 石子归并 3 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次 ...

  9. [51nod 1022] 石子归并v2 [dp+四边形不等式优化]

    题面: 传送门 思路: 加强版的石子归并,现在朴素的区间dp无法解决问题了 首先我们破环成链,复制一条一样的链并粘贴到原来的链后面,变成一个2n长度的序列,在它上面dp,效率O(8n^3) 显然是过不 ...

随机推荐

  1. win7查看某个端口被占用的解决方法

    1.开始---->运行---->cmd,或者是window+R组合键,调出命令窗口. 2.输入命令:netstat -ano,列出所有端口的情况.在列表中我们观察被占用的端口,比如是491 ...

  2. redis的ruby客户端(三)

    1. 介绍 clients这里列出了redis所支持的语言的所有客户端程序,其中就有ruby的.有这么多的客户端,说明要实现redis的客户端是不难的.其实你只要掌握一种语言的socket编程就可以实 ...

  3. VIM 配置python

    Pre-install sudo yum install automake gcc gcc-c++ kernel-devel cmake sudo yum install python-devel p ...

  4. HDU 4370 - 0 or 1 (SPFA+思维)

    题意:给一个N*N的矩阵C,和一个N*N的只由0和1组成的矩阵X. X满足以下条件: 1.X 12+X 13+...X 1n=1  2.X 1n+X 2n+...X n-1n=1  3.任意 i (1 ...

  5. javascript Date对象 之 获取时间

    javascript Date对象 --> 获取时间: 测试代码: <!DOCTYPE html> <html lang="en"> <head ...

  6. C# Winform 窗体传值 利用委托 子窗体传值给父窗体

    常用的Winform窗体传值有两种方式. 1.更改Form.designer.cs文件,将控件的设为Public,供子窗体访问. 在designer.cs文件的最后,找到你的控件声明. private ...

  7. 图像运动去模糊(Motion Deblurring)代码

    http://blog.csdn.net/qianliheshan/article/details/12853157 http://www.di.ens.fr/~whyte/ Efficient De ...

  8. C语言单元测试框架--EmbedUnit

    1.简介 Embedded Unit是个纯标准c构建的单元测试框架,主要用在嵌入式c的单体测试上,其主要特点是不依赖于任何C的标准库,所有的对象都是静态分配. 最早这个项目托管在SourceForge ...

  9. Django学习笔记之使用 Django项目开发框架

    Django 项目是一个定制框架,它源自一个在线新闻 Web 站点,于 2005 年以开源的形式被释放出来.Django 框架的核心组件有: 用于创建模型的对象关系映射 为最终用户设计的完美管理界面 ...

  10. Stalstack 连接管理配置

    Stalstack 连接管理配置 注:master端,minion端,配置完成.   Saltstack master 测试管理端minion链接状态. salt-key Accepted Keys: ...