Tree Construction(四边形优化dp)

原题: http://acm.hdu.edu.cn/showproblem.php?pid=3516

题意:

给出n个左上角到右下角的点,用向右和向上的边连起来,问边长和的最小值。

解析:

一开始以为点是随机分布的,状态方程都想不出来。

d p [ i , j ] dp[i,j] 表示连接 i i j j 的最短变长,显然 d p [ i , j ] = m i n ( d p [ i , k ] + d p [ k + 1 , j ] + ( X k + 1 X i ) + ( Y k Y j ) ) dp[i,j]=min(dp[i,k]+dp[k+1,j]+(X_{k+1}-X_{i})+(Y_k-Y_{j}))
讨论面那串是否符合四边形不等式: ( X k + 1 X a + Y k Y b ) + ( X k + 1 X c + Y k Y d ) < = ( X k + 1 X a + Y k Y c ) + ( X k + 1 X b + Y k Y d ) (X_{k+1}-X_a+Y_{k}-Y_b)+(X_{k+1}-X_c+Y_{k}-Y_d)<=(X_{k+1}-X_a+Y_{k}-Y_c)+(X_{k+1}-X_b+Y_{k}-Y_d) X b Y b < = X c Y c X_b-Y_b<=X_c-Y_c 相当于 y = x + b y=x+b 中的截距的相反数,所以下标越大值越大,故不等式成立。

#include<bits/stdc++.h>
using namespace std;
#define LL long long

int dp[1009][1009];
int best[1009][1009];
int x[1009],y[1009];
int n;

int main(){
    while(cin>>n){
        memset(dp,0x3f,sizeof dp);
        for(int i=1;i<=n;i++)
            scanf("%d%d",x+i,y+i),dp[i][i]=0,best[i][i]=i;
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                for(int k=best[i][j-1];k<=best[i+1][j];k++){
                    if(dp[i][k]+dp[k+1][j]+(x[k+1]-x[i])+(y[k]-y[j])<dp[i][j]){
                        dp[i][j]=dp[i][k]+dp[k+1][j]+(x[k+1]-x[i])+(y[k]-y[j]);
                        best[i][j]=k;
                    }
                }
            }
        }
        printf("%d\n",dp[1][n]);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/90767458