HDU 3516 Tree Construction (四边形不等式)

题意:给定一些点(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\n",f[1][n]); 
30     }
31 }

 

posted @ 2016-06-02 16:40  GFY  阅读(747)  评论(0编辑  收藏  举报