四边形不等式优化-石子合并

四边形不等式优化


四边形不等式定义

在oi历程中,常有如下的dp转移方程

(f(i,j)=min(f(i,k)+f(k+1,j)+w(i,j))) ((i<=k<j))
(f(i,j)=inf) ((i>j))
(f(i,j)=0) ((i==j)​)

根据转移,可以看出这是个(O(n^3))的时间复杂度

但是 我们可以根据一些性质,优化部分转移,使其时间复杂度将至(O(n^2))

四边形不等式的定义
如函数(w),满足
(w(i,j')+w(i',j)>= w(i,j)+w(i',j')) ((i<=i'<j<=j'))
则称(w)是满足四边形不等式的,或称具有凸完全单调性
可记作:交叉小于包含

性质

  1. 若形同上式的(dp)方程中,(w)函数满足凸完全单调性,则(f)也满足凸完全单调性
证明

(i==i')(j==j')
显然成立


(i<i'=j<j')
原式=(w(i,j')+w(j,j') <= w(i,j'))
(k=min(t)(f(i,j')=f(i,t)+f(t+1,j')+w(i,j')))
由于对称性(即下文中不等号右面的(j)(k)可以互换),则设(k<=j)

(f(i,j)+f(j,j')<=f(i,j)+f(k+1.j)+w(i,j)+f(j,j')+w(j,j')) (因为是最有决策,不等号成立)
(f(i,j)+f(j,j')<=f(i,j'))
利用数学归纳法得证


(i<i'<j<j')
(y=min(t)(f(i',j)=f(i,t)+f(t+1,j')+w(i,j')))
(z=min(t)(f(i,j')=f(i',t)+f(t+1,j)+w(i',j)))
由于对称性(同上),可以设(z<=y)

[f(i,j)+f(i',j')<=w(i,j)+w(i',j')+f(i',y)+f(i,z)+f(y+1,j')+f(z+1,j)$$; $$<=w(i,j)+w(i',j')+f(i',y)+f(i,z)+f(z+1,j')+f(y+1,j)$$; $$=f(i,j')+f(i',j)$$; 为什么这个东西成立呢? ]

因为他的成立的必要条件是(f(i',y)+f(i,z)+f(y+1,j')+f(z+1,j)<=f(i',y)+f(i,z)+f(z+1,j')+f(y+1,j))

可以看做是上述问题的规模缩小版。其最终情况会回归到前两种情景。


  1. 决策单调性

我们加速dp所使用的就是决策单调性,四边形不等式是为了引出他

设s(i,j)为f(i,j)的最有决策点

那么有

(s(i,j)<=s(i,j+1)<=s(i+1,j+1))

证明

(i>j)
显然成立


(i<j)

为了方便叙述,我们令(f_k(i,j))表示(f(i,j))(k)时的决策值
(f_{s(i,j)}(i,j)=f(i,j))

由于f满足四边形不等式
所以有
(f(k,j)+f(k',j+1)<=f(k,j+1)+f(k',j) (k<k'<j)​)
在不等式两边加上(w(i,j)+f(i,k-1)+w(i,j+1)+f(i,k'-1)​)
便可得出
(f_k(i,j)+f_{k'}(i,j+1) <= f_k(i,j+1)+f_{k'}(i,j)​)
(f_k(i,j)-f_{k'}(i,j)<=f_k(i,j+1)-f_{k'}(i,j+1)​)

可以发现,可以由左式推出右式
由于在(s(i,j)​)右边的决策点来说,必有(f_k(i,j)>=f(i,j)​)
还一定有 (f_s(i,j)(i,j+1)<=f_k(i,j+1)​)
当然,(f(i,j)​)的决策点不一定是(s(i,j)​)
但通过我们上面的证明,便可以确定,一定不小于(s(i,j)​)
便证明出来了(s(i,j)<=s(i,j+1)​)
剩下的一对也可以如此证明

(s)满足上面的关系.则称s关于区间包含关系单调

好(AO) 结束了上面的证明,便可以运用到(dp)中去了

这玩意写了我一个晚上qwq,为了保证正确性,边写边证

我们只需要处理这个决策点就可以啦

根据证明,在确定一个大区间([i,j])时,([i,j-1])([i+1,j])的最有决策点已经确定了。直接在范围内枚举就好了

关于时间复杂度么,不会证

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using std::max;
using std::min;

const int maxn=300;

int base[maxn];
int dp[maxn][maxn],s[maxn][maxn];
int MAX[maxn][maxn];

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&base[i]);
        base[i+n]=base[i];
    }
    for(int i=1;i<=n*2;i++)
        base[i]+=base[i-1];
    for(int i=1;i<=n*2;i++)
        s[i][i]=i;
    for(int l=2;l<=n;l++)
        for(int i=1;i<=(n*2)-l+1;i++)
        {
            int j=i+l-1;
            int x=s[i][j-1],y=s[i+1][j];
            dp[i][j]=0x7fffffff;
            MAX[i][j]=max(MAX[i][j-1],MAX[i+1][j])+base[j]-base[i-1];//最大值不满足四边形不等式,但最有决策一定出现在端点处
            for(int k=x;k<=y;k++)
                if(dp[i][k]+dp[k+1][j]+base[j]-base[i-1]<dp[i][j])
                {
                    dp[i][j]=dp[i][k]+dp[k+1][j]+base[j]-base[i-1];
                    s[i][j]=k;
                }
        }
    int ansMin=0x7fffffff,ansMax=0;
    for(int i=1;i<n;i++)
        ansMin=min(ansMin,dp[i][i+n-1]),
        ansMax=max(ansMax,MAX[i][i+n-1]);
    printf("%d
%d",ansMin,ansMax);
    return 0;
}
原文地址:https://www.cnblogs.com/Lance1ot/p/10392691.html