[HDU3516] Tree Construction [四边形不等式dp]

题面:

传送门

思路:

这道题有个结论:

把两棵树$\left[i,k\right]$以及$\left[k+1,j\right]$连接起来的最小花费是$x\left[k+1\right]-x\left[i\right]+y\left[k\right]-y\left[j\right]$

然后就明显可以区间dp了

设$dp\left[i\right]\left[j\right]$表示把闭区间$\left[i,j\right]$中的点连起来的最小花费,然后定义上面那个最小花费为$w\left(i,k,j\right)$

那么转移方程就比较显然了:

$dp\left[i\right]\left[j\right]=min\left(dp\left[i\right]\left[k\right]+dp\left[k+1\right]\left[j\right]+w\left(i,k,j\right)\right)$

 

证明一下可以看出,$w$函数在$k$不变的时候,是满足四边形不等式的

因此可以给$dp$套一个优化,在$O\left(n^2\right)$中解决

 

这道题目的重难点实际上就是求$w\left(i,k,j\right)$的表达式,求出来就很显然了

 

Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define inf 1e9
 6 using namespace std;
 7 inline int read(){
 8     int re=0,flag=1;char ch=getchar();
 9     while(ch>'9'||ch<'0'){
10         if(ch=='-') flag=-1;
11         ch=getchar();
12     }
13     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
14     return re*flag;
15 }
16 int n,x[1010],y[1010],dp[1010][1010],s[1010][1010];
17 int w(int l,int mid,int r){
18     return x[mid+1]-x[l]+y[mid]-y[r];
19 }
20 int main(){
21     int i,j,len,tmp,k;
22     while(~scanf("%d",&n)){
23     for(i=1;i<=n;i++) x[i]=read(),y[i]=read();
24         for(i=1;i<=n;i++) dp[i][i]=0,s[i][i]=i;
25         for(len=1;len<n;len++){
26             for(i=1;i<=n;i++){
27                 j=len+i;if(j>n) break;
28                 dp[i][j]=inf;
29                 for(k=s[i][j-1];k<=s[i+1][j]&&k<j;k++){
30                     if((tmp=dp[i][k]+dp[k+1][j]+w(i,k,j))<dp[i][j]){
31                         dp[i][j]=tmp;s[i][j]=k;
32                     }
33                 }
34             }
35         }
36         printf("%d\n",dp[1][n]);
37     }
38 }

 

posted @ 2018-03-18 11:18  dedicatus545  阅读(215)  评论(0编辑  收藏  举报