zoukankan      html  css  js  c++  java
  • 四边形不等式

    前言

    之前写过一篇关于斜率优化的文章:Link

    下面介绍另一种利用决策单调性来转移优化的方法。

    算法简介

    如果子问题的数目为 (Theta(n^2)),每个子问题需要用到 (Theta(n)) 个子问题的结果来转移,那么我们称它为 2D/1D 的问题。

    一般来说,它的状态转移方程是这样子的:

    [dp[i][j]=min_{ileq k<j}{dp[i][k]+dp[k+1][j]}+val(i,j) ]

    不难发现,这是区间 DP 的常用方程。

    如果直接进行状态转移,那么时间复杂度为 (Theta(n^3))

    但是,如果 (val(i,j)) 存在某些特殊的性质,我们就可以用四边形不等式对其进行优化。

    这里先介绍一下四边形不等式:

    • 定义 (1):如果 (forall lleq l'leq r'leq r,f(l,r')+f(l',r)leq f(l',r')+f(l,r)),则称函数 (f) 满足四边形不等式

    • 定义 (2):如果 (forall lleq l'leq r'leq r,f(l',r')leq f(l,r)),则称函数 (f) 满足区间包含单调性

    下面详细介绍一下关于它的一些小性质:

    • 性质 (1):函数 (f) 满足四边形不等式,当且仅当 (forall i<j,f(i+1,j)+f(i,j+1)leq f(i,j)+f(i+1,j+1))

    • 性质 (2):在上面的状态转移方程中,若 (val) 满足区间包含单调性和四边形不等式,则 (dp) 也满足四边形不等式。

    • 性质 (3):在上面的状态转移方程中,设 (dp) 的决策为 (s),且 (dp) 满足四边形不等式,则 (s[i][j-1]leq s[i][j]leq s[i+1][j])

    关于上面性质的证明如下:

    • 性质 (1) 的证明:

    用数学归纳法解释,比较简单。

    • 性质 (2) 的证明:

    考虑对区间长度归纳。

    当区间长度为 (1,2) 时,不难证明四边形不等式成立。

    假设当区间长度 (<j-i+1) 时,四边形不等式成立,下面证明当区间长度 (=j-i+1) 时成立。

    相当于去证明这个式子:(dp[i][j]+dp[i+1][j+1]leq dp[i][j+1]+dp[i+1][j])

    (dp[i+1][j]) 是由 (k=x) 转移得到,(dp[i][j+1]) 是由 (k=y) 转移得到,不妨设 (xleq y)

    这里先证明一下:(dp[x+1][j]+dp[y+1][j+1]leq dp[x+1][j+1]+dp[y+1][j])

    事实上,由归纳假设我们知道:(dp[x+1][j]-dp[x+1][j+1]leq dp[x+2][j]-dp[x+2][j+1])

    以此类推即可得到上面我们想证的式子是成立的。

    此时将 (k=x) 代入 (dp[i][j]),将 (k=y) 代入 (dp[i+1][j+1]) 得到:

    [egin{align*}& dp[i][j]+dp[i+1][j+1]\&leq dp[i][x]+dp[x+1][j]+val(i,j)+dp[i+1][y]+dp[y+1][j+1]+val(i+1,j+1)\&leq dp[i][x]+dp[x+1][j+1]+val(i,j+1)+dp[i+1][y]+dp[y+1][j]+val(i+1,j)\&leq dp[i][j+1]+dp[i+1][j]end{align*} ]

    得证!

    • 性质 (3) 的证明:

    先证明:(s[i][j]leq s[i+1][j])

    我们设 (dp[i][j]) 是由 (s[i][j]=d) 转移得到的。

    (h[k][i][j]=dp[i][k]+dp[k+1][j],forall k<d)

    那么有 (dp[i][j]leq h[k][i][j]),接下来只需证明:(dp[i+1][j]leq h[k][i+1][j]) 即可。

    [egin{align*}& (dp[i+1][j]-h[k][i+1][j])-(dp[i][j]-h[k][i][j])\&=(dp[i+1][j]+h[k][i][j])-(h[k][i+1][j]+dp[i][j])\&leq (dp[i+1][d]+dp[d+1][j]+dp[i][k]+dp[k+1][j])-(dp[i+1][k]+dp[k+1][j]+dp[i][d]+dp[d+1][j])\&=(dp[i+1][d]+dp[i][k])-(dp[i+1][k]+dp[i][d])end{align*} ]

    由于 (dp) 满足四边形不等式,故我们有:(forall i+1leq k<d,dp[i+1][d]+dp[i][k]leq dp[i+1][k]+dp[i][d])

    因此,(dp[i+1][j]-h[k][i+1][j]leq dp[i][j]-h[k][i][j]leq 0)

    于是,(s[i][j]leq s[i+1][j])

    同理可得:(s[i][j-1]leq s[i][j])

    得证!

    例题讲解

    下面提供一道较为基础的题目:

    例题1:[NOI1995]石子合并

    (Large{ ext{Description:}})

    在一个圆形操场的四周摆放 (n) 堆石子,现要将石子有次序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记为该次合并的得分。

    需要计算出将 (n) 堆石子合并成一堆的最小得分和最大得分。

    数据范围:(nleq 100)

    (Large{ ext{Solution:}})

    首先,这题可以想到用区间 DP 求解,再加上断环成链的思想,我们可以考虑到上面说的 2D/1D 的常规状态转移方程:

    最大值比较简单,直接取两个端点的最大值即可;

    最小值需要用下面的状态转移方程来实现:

    [dp[i][j]=min_{ileq k<j}{dp[i][k]+dp[k+1][j]}+sum[j]-sum[i-1] ]

    这里按照上面的证明过程,不难得到 (dp) 是满足四边形不等式的。

    那么利用性质 (2,3) 就可以写出下面的代码……(四边形不等式的优化大致上就是一个模板,会灵活应用即可)

    时间复杂度:(Theta(n^2))

    (Large{ ext{Code:}})

    #include<bits/stdc++.h>
    #define Re register
    using namespace std;
    
    const int N=205;
    
    int n,a[N],sum[N];
    
    int DP[N][N];
    
    int s[N][N],dp[N][N];
    
    inline int rd()
    {
    	char ch=getchar();
    	int x=0,f=1;
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(Re int i=1;i<=n;i++)
    	{
    		a[i]=rd();
    		a[n+i]=a[i];
    	}
    	for(Re int i=1;i<=n+n;i++)
    	{
    		sum[i]=sum[i-1]+a[i];
    		s[i][i]=i;
    	}
    	for(Re int i=n+n;i>0;i--)
    	{
    		for(Re int j=i+1;j<=n+n;j++)
    		{
    			DP[i][j]=max(DP[i+1][j],DP[i][j-1])+sum[j]-sum[i-1];
    			int Mindp=0x3f3f3f3f,Mins;
    			for(Re int k=s[i][j-1];k<=s[i+1][j];k++)
    			{
    				if(Mindp>dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])
    				{
    					Mindp=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
    					Mins=k;
    				}
    			}
    			dp[i][j]=Mindp;
    			s[i][j]=Mins;
    		}
    	}
    	int ans1=0x3f3f3f3f,ans2=0;
    	for(Re int i=1;i<=n+1;i++)
    	{
    		ans1=min(ans1,dp[i][i+n-1]);
    		ans2=max(ans2,DP[i][i+n-1]);
    	}
    	printf("%d
    %d",ans1,ans2);
    	return 0;
    }
    

    练习题

    1. 山区建小学

    2. [IOI2000]邮局

  • 相关阅读:
    NYOJ 625 笨蛋的难题(二)
    NYOJ 102 次方求模
    ZJU Least Common Multiple
    ZJUOJ 1073 Round and Round We Go
    NYOJ 709 异形卵
    HDU 1279 验证角谷猜想
    BNUOJ 1015 信息战(一)——加密程序
    HDU 1202 The calculation of GPA
    "蓝桥杯“基础练习:字母图形
    "蓝桥杯“基础练习:数列特征
  • 原文地址:https://www.cnblogs.com/kebingyi/p/14347709.html
Copyright © 2011-2022 走看看