• 【HDOJ】【3516】Tree Construction


    DP/四边形不等式


      这题跟石子合并有点像……

    dp[i][j]为将第 i 个点开始的 j 个点合并的最小代价。

    易知有 dp[i][j]=min{dp[i][j] , dp[i][k-i+1]+dp[k+1][j-(k-i+1)]+w(i,k,j)}

                              (这个地方一开始写错了……)

    即,将一棵树从k处断开成(i,k)和(k+1,i+j-1)两棵树,再加上将两棵树连起来的两条树枝的长度w(i,k,j)

    其中,$ w(i,k,j)=x[k+1]-x[i]+y[k]-y[i+j-1] $

    那么根据四边形不等式易知 $s[i][j-1] leq k leq s[i+1][j-1] $

      如果觉得上面那种不好懂,那我们来看个好懂的:

    dp[i][j]表示将第 i 个点到第 j 个点合并的最小代价。

    易知有 dp[i][j]=min{ dp[i][j],dp[i][k]+dp[k+1][j]+w(i,k,j) }

    即,将一棵树从k处断开成(i,k)和(k+1,j) 两棵树,再加上将两棵树连起来的两条树枝的长度w(i,k,j)

    w(i,k,j)的定义与上同

    那么根据四边形不等式易知 $s[i][j-1] leq k leq s[i+1][j] $

      其实,两种表示方法是一样的,递推时都按照区间长度为阶段进行递推(想一想,第二种中 (i,j-1) 和 (i+1,j) 的长度是不是 都是(i,j)的长度-1?)

      只是第二种写法的方程看上去好看,也好写……sigh那我写第一种干嘛T_T算了不改了

      反正基本就是石子合并的原题啦~除了w函数的定义不同……

     1 //HDOJ 3516
     2 #include<cmath>
     3 #include<vector>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<cstdlib>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define rep(i,n) for(int i=0;i<n;++i)
    10 #define F(i,j,n) for(int i=j;i<=n;++i)
    11 #define D(i,j,n) for(int i=j;i>=n;--i)
    12 #define pb push_back
    13 #define CC(a,b) memset(a,b,sizeof(a))
    14 using namespace std;
    15 int getint(){
    16     int v=0,sign=1; char ch=getchar();
    17     while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();}
    18     while(isdigit(ch))  {v=v*10+ch-'0'; ch=getchar();}
    19     return v*sign;
    20 }
    21 const int N=1010,INF=~0u>>2;
    22 const double eps=1e-8;
    23 /*******************template********************/
    24 //#define debug
    25 int x[N],y[N],dp[N][N],s[N][N];
    26 int main(){
    27 #ifndef ONLINE_JUDGE
    28     freopen("input.txt","r",stdin);
    29 //    freopen("output.txt","w",stdout);
    30 #endif
    31     int n;
    32     while(scanf("%d",&n)!=EOF){
    33         F(i,1,n) x[i]=getint(),y[i]=getint();
    34         F(i,1,n){
    35             dp[i][1]=0;
    36             s[i][1]=i;
    37         }
    38         F(i,1,n-1){
    39             dp[i][2]=x[i+1]-x[i]+y[i]-y[i+1];
    40             s[i][2]=i;
    41         }
    42         #ifdef debug
    43         F(i,1,n-1) printf("%d ",dp[i][2]);
    44         printf("
    ");
    45         #endif
    46         F(j,3,n)
    47             F(i,1,n-j+1){
    48                 dp[i][j]=INF;
    49                 F(k,s[i][j-1],s[i+1][j-1]){
    50                     int tmp=y[k]-y[i+j-1]+x[k+1]-x[i]+dp[i][k-i+1]+dp[k+1][j-(k-i+1)];
    51                     #ifdef debug
    52                     printf("i=%d k=%d j=%d
    ",i,k,j);
    53                     printf("dp[i][k-i+1]=%d dp[k+1][j-k]=%d
    ",dp[i][k-i+1],dp[k+1][j-k]);
    54                     #endif
    55                     if (tmp<dp[i][j]){
    56                         s[i][j]=k;
    57                         dp[i][j]=tmp;
    58                     }
    59                 }
    60             }
    61         #ifdef debug
    62         F(j,1,n){
    63             F(i,1,n) printf("%d ",dp[i][j]);
    64             printf("
    ");
    65         }
    66         F(j,1,n){
    67             F(i,1,n) printf("%d ",s[i][j]);
    68             printf("
    ");
    69         }
    70         #endif
    71         printf("%d
    ",dp[1][n]);
    72     }
    73     return 0;
    74 }
    View Code(156MS 9076K)
  • 相关阅读:
    20165326 java第二周学习笔记
    20165326 选做1
    20165326 java第一周学习笔记
    2018-2019-1 20165325 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165325 20165320 20165337 实验二 固件程序设计
    2018-2019-1 20165325 《信息安全系统设计基础》第六周学习总结
    2018-2019-1 20165325 《信息安全系统设计基础》第五周学习总结
    2018-2019-1 20165325 《信息安全系统设计基础》第四周学习总结
    2018-2019-1 20165325 《信息安全系统设计基础》第三周学习总结
    2018-2019-1 20165325 《信息安全系统设计基础》第二周学习总结
  • 原文地址:https://www.cnblogs.com/Tunix/p/4318883.html
Copyright © 2020-2023  润新知