zoukankan      html  css  js  c++  java
  • 石子合并(四边形不等式优化dp) POJ1160

    该来的总是要来的————————

    经典问题,石子合并。

      对于 f[i][j]= min{f[i][k]+f[k+1][j]+w[i][j]}

    From 黑书

    凸四边形不等式:w[a][c]+w[b][d]<=w[b][c]+w[a][d](a<b<c<d)

    区间包含关系单调: w[b][c]<=w[a][d](a<b<c<d)

    定理1:  如果w同时满足四边形不等式和决策单调性 ,则f也满足四边形不等式

    定理2:  若f满足四边形不等式,则决策s满足 s[i][j-1]<=s[i][j]<=s[i+1][j]

    定理3: w为凸当且仅当w[i][j]+w[i+1][j+1]<=w[i+1][j]+w[i][j+1]   

    简要证明:

    若w[a][c]+w[b][d]<=w[b][c]+w[a][d],归纳证明f[a][c]+f[b][d]<=f[b][c]+f[a][d]

      设f[a][d]最优决策是在s取到,f[b][c]最优决策在t取到,设s<t,反之同理

      可知a<s<t<c<d

        f[a][c]+f[b][d]<=f[a][s]+f[s+1][c]+w[a][c] + f[b][t]+f[t+1][d]+w[b][d]

                =f[a][s]+f[s+1][c]+w[a][d] + f[b][t]+f[t+1][d]+w[b][c]

               <=f[a][s]+w[a][d]+f[s+1][d] + f[b][t]+w[b][c]+f[t+1][c]         归纳得到 sc+td<sd+tc  起始条件即定理3

               =f[a][d]+f[b][c]

    得证.

    若f[a][c]+f[b][d]<=f[b][c]+f[a][d],则s[i][j-1]<=s[i][j]<=s[i+1][j]

      仅证s[i][j-1]<=s[i][j],右边同理

      记f_k[i][j]=f[i][k]+f[k+1][j]+w[i][j]

      记s点为[i,j]最优点,t点为[i,j+1]最优点,

      则只需证明 在[i,j+1]决策时, 取s点能够比取在k∈[i,s-1]的点更优即可

        即证明 f_s[i,j+1]<=f_k[i,j+1]

      又因为f_s[i,j]<=f_k[i,j]

         只需证明 0 <= f_k[i,j] - f_s[i,j] <= f_k[i,j+1] - f_s[i,j+1]

          可发现右边即 f_k[i,j] + f_s[i,j+1] <= f_k[i,j+1] + f_s[i,j]  

          展开后即: f[k][j] + f[s][j+1] <= f[k][j+1] + f[s][j]

          正是 k<s<j<j+1 的四边形不等式

    得证.

    一般利用定理3证明凸函数,然后利用定理2的结论 s[i][j-1]<=s[i][j]<=s[i+1][j]

      就能够使得复杂度由O(n^3)降低为O(n^2)

    详细证明参见《动态规划算法的优化技巧》--毛子青(会因为论文用i,j,i',j'搞得雾水,但是慢慢推一下就能够出来)

    #include <cstdio>
    #include <cstring>
    #define N 1005
    int s[N][N],f[N][N],sum[N],n;
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            memset(f,127,sizeof(f));
            sum[0]=0;
            for(int i=1; i<=n; i++){
                scanf("%d",&sum[i]);
                sum[i]+=sum[i-1];
                f[i][i]=0;
                s[i][i+1]=i;
            }
            for(int i=1; i<=n; i++)
                f[i][i+1]=sum[i+1]-sum[i-1];
    
            for(int i=n-2; i>=1; i--)
                for(int j=i+2; j<=n; j++)
                    for(int k=s[i][j-1]; k<=s[i+1][j]; k++)
                    if(f[i][j]>f[i][k]+f[k+1][j]+sum[j]-sum[i-1])
                    {
                        f[i][j]=f[i][k]+f[k+1][j]+sum[j]-sum[i-1];
                        s[i][j]=k;
                    }
        
            printf("%d
    ",f[1][n]);
        }
        return 0;
    }

    值得注意的是:若是求石子合并的最大值,则不能用四边形不等式。可以证明 f[i,j]=max(f[i+1][j],f[i][j-1])+w[i][j] 

    POJ1160

    f[i][j]=max(f[k][j-1]+w[k+1][i])

      其中f[i][j]表示前i个村落有j个邮电局,w[i][j]表示[i,j]区间上安装一个邮电局最短路径和

    其中w[i][j]邮电局必然是安装在(i+j)/2(中位数)的村落中,若(i+j)/2不为整数,则中间两个村落都可以。证明可以看《算法导论》

    至于四边形不等式,这次,可以直接容易得到 s[i][j-1]<=s[i][j]<=s[i+1][j] 稍微证明下就可以出来,凭感觉都是对的。

    #include <cstdio>
    #include <cstring>
    #define min(x,y) (x>y?y:x)
    int v,p,a[305],sum[305],w[305][305],f[305][35],s[305][35];
    int main()
    {
        memset(f,127,sizeof(f));
        scanf("%d%d",&v,&p);
        for(int i=1; i<=v; i++){
            scanf("%d",&a[i]);
            sum[i]=a[i]+sum[i-1];
        }
        for(int i=1; i<=v; i++){
            w[i][i]=0;
            for(int j=i+1; j<=v; j++){
                w[i][j]=sum[j]-sum[(i+j)/2]-sum[(i+j)/2-1]+sum[i-1];
                if((i+j)%2!=0) w[i][j]-=a[(i+j)/2];
            }
        }
        for(int i=1; i<=v; i++)
            f[i][1]=w[1][i];
        for(int j=2; j<=p; j++){
            s[v+1][j]=v-1;
            for(int i=v; i>=j; i--)
            {
                for(int k=s[i][j-1]; k<=s[i+1][j]; k++)
                if(f[i][j]>f[k][j-1]+w[k+1][i])
                {
                    f[i][j]=f[k][j-1]+w[k+1][i];
                    s[i][j]=k;
                }
            }
        }
        printf("%d",f[v][p]);
        return 0;
    }
  • 相关阅读:
    XML认识
    servlet清晰理解
    JDBC基本知识
    JSP中的路径
    JavaBean基础
    JSP执行过程详解
    JDBC连接mysql
    JSP简易留言板
    Jmeter性能测试之基础知识(一)
    linux下安装redis并开机自启动
  • 原文地址:https://www.cnblogs.com/Mathics/p/3885745.html
Copyright © 2011-2022 走看看