题意:给定一些点(xi,yi)(xj,yj)满足:i<j,xi<xj,yi>yj。用下面的连起来,使得所有边的长度最小?
思路:考虑用区间表示,f[i][j]表示将i到j的点连起来的最小代价。
那么f[i][j]=min(f[i][k]+f[k+1][j]+cost(i,j)
cost(i,j)=a[k].y-a[j].y+a[k+1].x-a[i].x;
看起来和四边形不等式有关系,我们需要证明以下(a<b<c<d)
cost(a,c)+cost(b,d)<=cost(a,d)+cost(b,c)
cost(b,c)<=cost(a,d)
有个结论:w为凸当且仅当:cost(i,j)+cost(i+1,j+1)<=cost(i+1,j)+cost(i,j+1)
这个证明只需要固定i,j中的某一个,然后移动另一个即可.
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int f[1005][1005],s[1005][1005],n; 7 struct Point{ 8 int x,y; 9 }a[500005]; 10 int cost(int i,int j,int k){ 11 if (k>=j) return 0x3f3f3f3f; 12 return a[k].y-a[j].y+a[k+1].x-a[i].x; 13 } 14 int main(){ 15 while (~scanf("%d",&n)){ 16 for (int i=1;i<=n;i++){ 17 scanf("%d%d",&a[i].x,&a[i].y); 18 } 19 for (int i=1;i<=n;i++) s[i][i]=i; 20 memset(f,0,sizeof f); 21 for (int L=2;L<=n;L++) 22 for (int i=1;i+L-1<=n;i++){ 23 int j=L+i-1;f[i][j]=0x3f3f3f3f; 24 for (int k=s[i][j-1];k<=s[i+1][j];k++){ 25 int tmp=f[i][k]+f[k+1][j]+cost(i,j,k); 26 if (tmp<f[i][j]) f[i][j]=tmp,s[i][j]=k; 27 } 28 } 29 printf("%d ",f[1][n]); 30 } 31 }