• poj1160


       题目大意:在一个一维坐标轴上有v个(1<=v<=300)村庄,要建p(1<=p<=30)个邮局,每个村庄都到最近的邮局,要求最小的距离和。

         四边形不等式,据说黑书上写得很高深。

       描述是这样的:令(a<=b<=c<=d,i<=k<j),若w[a][c]+w[b][d]<=w[a][d]+w[b][c],m[i][j]=min OR max{m[i][k]+m[k+1][j]+w[i][j]}则m[a][c]+m[b][d]<=m[a][d]+m[b][c]。

       对于这个式子,个人觉得没必要深究,读者读读题目就应该知道自己要求的m[i][j]定义,取min或者max。我也不会证明,只能弱弱感受到是这么回事。(毕竟那些都不重要,因为不涉及最后求解结果)

         最重要的是这个式子,假设s[i][j]是对应取到m[i][j]的最优解(s当然是solution的意思了,关于解的描述要细细考虑,因为它并不用是一种很确切的表示,只需要是一个关键的量就可以)。PS:我觉得,我要是不解释这个关键量,很多人肯定会黑我的,但是我真的不知道怎么表达。看代码中的注解吧。

        四边形不等式最大优化是s[i][j]一定介于s[k=i-1 或者 k=i+1][j]、s[i][j+1]之间。(也有很多博客上写成s[i-1][j]<=s[i][j]<=s[i][j+1])这样对于我们搜索关于s[i][j]的值时范围大大缩短了。对于s[i][max_(i)]可以用我们通常容易想到的dp方程线性效率解决。而s[i][1]到s[i][max_(i)-1]这一段的解,总共的效率可以缩短到线性。 

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 const int infinity=(-1)^(1<<31);
     7 const int V=305;
     8 const int P=35;
     9 int dp[V][P], s[V][P];
    10 int atx[V],sum[V];
    11 inline int setat(int i,int j){
    12     return (i+j)>>1;
    13 }
    14 int move_all(int fr,int ba){
    15     //printf("move from %d to %d = %d
    ",fr,ba,(sum[ba]-sum[fr])-atx[fr]*(ba-fr));
    16     return (sum[ba]-sum[fr])-atx[fr]*(ba-fr);
    17 }
    18 int S(int i,int j){
    19     int pos=setat(i,j);
    20     int ret=move_all(pos,j);
    21     ret += (atx[pos]-atx[i])*(pos-i+1)-move_all(i,pos);
    22     return ret;
    23 }
    24 int DP(int v,int p){
    25     sort(atx+1,atx+1+v);
    26     for(int i=v;i>=1;i--) atx[i]-=atx[1];
    27     for(int i=1;i<=v;i++) sum[i]=sum[i-1]+atx[i];
    28     //for(int i=1;i<=v;i++) printf("%3d ",atx[i]); printf("
    ");
    29     for(int i=1;i<=v;i++)
    30         dp[i][1]=S(1,i), s[i][1]=setat(1,i); //printf("1 --> %4d, %d
    ",i,dp[i][1]);
    31     if(p >= 2)
    32     for(int i=2;i<=v;i++){
    33         int maxj=min(i,p);
    34         dp[i][maxj]=infinity;
    35         for(int k=maxj-1;k<i;k++)
    36         if(dp[k][maxj-1]+S(k+1,i) < dp[i][maxj])
    37             dp[i][maxj]=dp[k][maxj-1]+S(k+1,i), s[i][maxj]=k;
    38         //printf("dp[%d][%d] = %d, s[i][maxj] = %d
    ",i,maxj,dp[i][maxj],s[i][maxj]);
    39         for(int j=maxj-1;j>=2;j--){
    40             dp[i][j]=infinity;
    41             for(int k=s[i-1][j];k<=s[i][j+1];k++)
    42             if(dp[k][j-1]+S(k+1,i) < dp[i][j]){
    43                 dp[i][j]=dp[k][j-1]+S(k+1,i);
    44                 s[i][j]=k;
    45             }
    46         }
    47     }
    48     return dp[v][p];
    49 }
    50 int main()
    51 {
    52     int v,p;
    53     while(scanf("%d%d",&v,&p) != EOF){
    54         for(int i=1;i<=v;i++)
    55             scanf("%d",&atx[i]);
    56         printf("%d
    ",DP(v,p));
    57     }
    58     return 0;
    59 }
    View Code

      个人觉得,在很多性质上,它跟斜率优化dp很像,甚至可以说斜率优化dp是最特殊的一类四边形不等式dp。斜率优化的dp中,最优化只根一个值有关,因为它保持后来无关单调。四边形不等式,把最优解的可选方案限制起来。

      我也是四边形不等式的初学者,希望路过的大牛不吝赐教。

  • 相关阅读:
    layui穿梭框内容溢出解决办法
    location之alias浅析
    Semaphore和SemaphoreSlim实现并发同步
    Barrier实现并发同步
    CountdownEvent实现并发同步
    AutoResetEvent实现并发同步
    TrieTree树
    EncryptByPassPhrase与DecryptByPassPhrase的浅说
    一个mp4转gif的网站
    vue轮播图(可随父元素高宽自适应)
  • 原文地址:https://www.cnblogs.com/karlvin/p/3330896.html
Copyright © 2020-2023  润新知