四边形不等式学习笔记

· · 算法·理论

在区间 dp 中,经常会出现这样的转移方程:

\min_{i\le k<j}({dp_{i,k},dp_{k+1,j}+w(i,j)}) & i<j\\ 0 & i=j \\ \infty & i>j\\ \end{cases}

定义

此时如果 i\le i' \le j \le j' 并且有:

w(i,j)+w(i',j')\le w(i,j')+w(i',j)

那么称函数 w 满足四边形不等式。
可以得到两个定理:

定理 1

此时 dp 满足四边形不等式。即 dp_{i,j}+dp_{i',j'}\le dp_{i,j'}+dp_{i',j}。 :::info[证明]

signed main(){ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); heffo_hard::solve(); return 0; } / heffo_hard 定义dis[i][j]:考虑在[i,j]中放置1个邮局的最小距离和(在中间放置) 所以dis[i][j]=bs(a[k]-a[(i+j)>>1]); /

但是现在这份代码过不了,时间复杂度为 $\mathcal{O}(PV^2)$,用什么优化呢?四边形不等式!  
发现 dis 是满足四边形不等式的,所以我们可以对 $k$  的取值范围进行优化,优化完的代码如下:
```cpp
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
#define piii pair<pii, int>
#define pll pair<ll, ll>
#define plll pair<pll, ll>
#define pref static inline
#define fi first
#define se second
using namespace std;
int n,p,a[3005],dis[3005][3005],dp[3005][305],s[3005][305];
namespace heffo_hard{
    pref void solve(){
        cin>>n>>p;
        for(int i=1;i<=n;++i){
            cin>>a[i];
        }
        sort(a+1,a+1+n);//排序(放置到轴上)
        for(int i=1;i<=n;++i){
            dis[i][i]=0;
            for(int j=i+1;j<=n;++j){
                int mid=(i+j)>>1;
                dis[i][j]=dis[i][j-1]+a[j]-a[mid];
            }
        }

        memset(dp,0x3f,sizeof(dp));
        dp[0][0]=0;
        for(int i=1;i<=n;++i){
            dp[i][1]=dis[1][i];
            s[i][1]=0;
        }
        for(int j=2;j<=p;++j){
            s[n+1][j]=n;
            for(int i=n;i>=j;--i){
                for(int k=s[i][j-1];k<=min(i-1,s[i+1][j]);++k){
                    int tmp=dp[k][j-1]+dis[k+1][i];
                    if(tmp<dp[i][j]){
                        dp[i][j]=tmp;
                        s[i][j]=k;
                    }
                }
            }
        }
        cout<<dp[n][p];
    }
};

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    heffo_hard::solve();
    return 0;
}
/*
heffo_hard
定义dis[i][j]:考虑在[i,j]中放置1个邮局的最小距离和(在中间放置)
所以dis[i][j]=bs(a[k]-a[(i+j)>>1]);
*/

现在的时间复杂度是 \mathcal{O}(PV),可以通过本题。
制作不易,可以点个 star 吗?
如果有问题欢迎评论。