题面:
思路:
这道题有个结论:
把两棵树$left[i,k ight]$以及$left[k+1,j ight]$连接起来的最小花费是$xleft[k+1 ight]-xleft[i ight]+yleft[k ight]-yleft[j ight]$
然后就明显可以区间dp了
设$dpleft[i ight]left[j ight]$表示把闭区间$left[i,j ight]$中的点连起来的最小花费,然后定义上面那个最小花费为$wleft(i,k,j ight)$
那么转移方程就比较显然了:
$dpleft[i ight]left[j ight]=minleft(dpleft[i ight]left[k ight]+dpleft[k+1 ight]left[j ight]+wleft(i,k,j ight) ight)$
证明一下可以看出,$w$函数在$k$不变的时候,是满足四边形不等式的
因此可以给$dp$套一个优化,在$Oleft(n^2 ight)$中解决
这道题目的重难点实际上就是求$wleft(i,k,j ight)$的表达式,求出来就很显然了
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 ",dp[1][n]); 37 } 38 }