一、四边形不等式基本理论

在动态规划的转移方程中,常见这样一种转移方程:

这两个定理证明在赵爽的《动态规划加速原理之四边形不等式》中给出了相关的证明。


【题意】给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小.

【分析】

dp(i,j)=min(dp(i-1,k)+w(k+1,j)) , i-1<=k<j  s(i-1,j)<=k<=s(i,j+1)

w(i,j)=w(i,j-1)+val[j]-val[(j+i)/2] , i<j<=n

dp(1,i)=w(1,i), w(i,i)=0, s(1,i)=0

对于函数w(i,j)有人可能疑问,从ij建一座邮局,对于邮局位置k,(i<=k<=j),这是一个凹区间,k选在i ,j的中间位置w(i,j)才是最小的,如何j-i是一个奇数,那么中间的两个数都是距离最小的点。对于w满足四边形不等式和区间单调性(本人表示不大会证,一般动态转移方程类似,n^3不能解决的问题,都是这么搞吧)。于是,我们限制了原方程中k的取值范围,得到了O(n^2)算法。

【AC代码】
#include <iostream>
#include <cstdio>
using namespace std;
#define inf 0x7ffffff
#define MIN(a,b) ((a)<(b)?(a):(b))
int dp[31][301];
int val[301];
int w[301][301];
int s[31][301];//表示前i-1个邮局的城市数

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1; i<=n; ++i)
        {
            scanf("%d",&val[i]);
        }
        for(int i=1; i<=n; ++i)
        {
            w[i][i]=0;
            for(int j=i+1; j<=n; ++j)
            {
                w[i][j]=w[i][j-1]+val[j]-val[(i+j)/2];
            }
        }
        //init1.
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=m; ++j)
            {
                dp[j][i]=inf;
            }
        }
        //init2.
        for(int i=1; i<=n; ++i)
        {
            dp[1][i]=w[1][i];
            s[1][i]=0;
        }
        //dp.
        for(int i=2; i<=m; ++i)
        {
            s[i][n+1]=n;//s[i][j]定义为使得dp(i,j)对应的决策的最大值
            for(int j=n; j>i; --j)
            {
                for(int k=s[i-1][j]; k<=s[i][j+1]; ++k)//四边形优化
                {
                    if(dp[i-1][k]+w[k+1][j]<dp[i][j])
                    {
                        s[i][j]=k;
                    }
                    dp[i][j]=MIN(dp[i][j],dp[i-1][k]+w[k+1][j]);
                }
            }
        }
        printf("%d\n",dp[m][n]);
    }
    return 0;
}