题目链接
题意:
二维坐标上,给出n个点,x严格单增,y严格单减。要求将这些点构成一棵树,其中边的方向只能是x轴正向和y轴正向。问树中所有边的长度之和最短为多少。
分析:
因为规定了变得方向,所以根节点坐标应该不在第一个点右边,也应该不在最后一个点上面。容易感觉到根节点一定就在(a[1].x,a[n].y)处。
dp[le][ri]=min{dp[le][k]+dp[k+1][ri]+a[k+1].x-a[le].x+a[k].y-a[ri].y}
这个题目的四边形不等式不会证(从来就没会过)。
下面证明在满足四边形不等式的前提下,决策满足单调性:
令m[le,ri]=dp[le][ri],该区间的决策k为s[le,ri]
有m[le,ri]=m[le,k]+m[k+1,ri]+a[k+1].x-a[le].x+a[k].y-a[ri].y
下面证明s[i,j-1]<=s[i,j]<=s[i+1,j]
先证明s[i,j]<=s[i+1,j]
设 d=s[i,j],设k<=d
则有
mk[i,j]>=md[i,j]
下面需要证明
mk[i+1,j]>=md[i+1,j]
引理: mk[i+1,j]−md[i+1,j]>=mk[i,j]−md[i,j]
由引理知
mk[i+1,j]−md[i+1,j]>=mk[i,j]−md[i,j]>=0
故 mk[i+1,j]>=md[i+1,j], 即[i+1,j]的决策点绝不会在[i,j]决策点左边。
证毕。
关于引理的证明:
mk[i+1,j]−md[i+1,j]>=mk[i,j]−md[i,j]>=0
所以待证式子等价于
m[i+1,k]−m[i+1,d]>=m[i,k]−m[i,d]
(消去,化简)
即
m[i+1,k]+m[i,d]>=m[i,k]+m[i+1,d]
因为k∈[i+1,j] (这是因为考虑[i+1,j]内的决策点), 所以
i<i+1<=k<=d
,满足四边形不等式的条件,所以
m[i+1,k]+m[i,d]>=m[i,k]+m[i+1,d],引理证毕。
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define ysk(x) (1<<(x))
const int INF =0x3f3f3f3f;
const int maxn= 1000 ;
int n,s[maxn+10][maxn+10],dp[maxn+10][maxn+10];
struct Node
{
int x,y;
}a[maxn+10];
int main()
{
std::ios::sync_with_stdio(false);
while(cin>>n)
{
for1(i,n) cin>>a[i].x>>a[i].y;
for1(i,n)
{
dp[i][i]=0;
s[i][i]=i;
}
for(int add=1;add<n;add++)
{
for(int le=1;le+add<=n;le++)
{
int ri=le+add;
int L=s[le][ri-1];
int R=s[le+1][ri];
dp[le][ri]=INF;
for(int k=L;k<=R&&k<ri;k++)
{
int ret=dp[le][k]+dp[k+1][ri]+a[k+1].x-a[le].x+a[k].y-a[ri].y;
if(ret<=dp[le][ri])
{
dp[le][ri]=ret;
s[le][ri]=k;
}
}
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}