• bzoj 1084 DP


      首先对于m==1的情况非常容易处理(其实这儿因为边界我错了好久。。。),直接DP就好了,设f[i][k]为这个矩阵前i个选k个矩阵的最大和,那么f[i][k]=max(f[j][k-1]+sum[j+1][i]),那么对于m==2的时候类似与m=1的时候,设w[i][j][k]为左面的一行前i个中,右面的一行前j个中,一共选k个矩阵能选取得最大矩阵。

      那么转移也比较明显,有一下几种转移

      w[i][j][k]=max(w[i-1][j][k],w[i][j-1][k])这种情况代表什么都不选。

      w[i][j][k]=max(w[ii][j][k-1]+sum[ii+1][i][0])这种情况代表在左面一行重新确定i这个位置如何选取。

      类似的w[i][j][k]=max(w[i][jj][k-1]+sum[jj+1][j][1])这种情况代表在右面一行重新确定i这个位置如何选取。 

      当i==j的时候w[i][j]=max(w[ii][ii]+sum[ii+1][i][2]),这样就代表选了一个占两行的矩形,然后注意枚举的边界就可以了。

      反思:开始我的想法是w[i][k]代表两行矩阵前i个选k个矩阵的最大值,我们可以知道选取矩阵的方法肯定是若干段只选取一行的组合,然后由选取两行的隔开,那么我们可以枚举i代表在i出选取占两行的矩形(这个矩形的长可以为0),那么w[i][k]=max(w[j][k]+f[j+1][ii]+sum[ii][i]),这个转移就是先枚举上一次的断点,然后后枚举上一断点到i的情况,就是一段只选取一行的加上一个占两行的最大值,那么首先要处理每一行的f[i][j][k]值,代表i,j段选取k个矩阵的最大值。后来因为转移的时候枚举边界特别麻烦,没有调出来,再仔细想想之后发现这种转移由于状态数太少,没办法准确的表达每一个状态,所以转移起来非常麻烦,所以就加了一维,可以准确的表达所有状态,而且转移十分方便,复杂度也降低了一个k(因为上一种方法需要枚举左右两行各选多少矩形),总之,还是自己太弱了。。。

      

    /**************************************************************
        Problem: 1084
        User: BLADEVIL
        Language: C++
        Result: Accepted
        Time:88 ms
        Memory:1672 kb
    ****************************************************************/
     
    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 100
    #define maxm 20
     
    using namespace std;
     
    int n,m,k;
    int a[maxn][maxn],sum[maxn][maxn],f[maxn][maxm],w[maxn][maxn][maxm];
     
    int main(){
        scanf("%d%d%d",&n,&m,&k);
        sum[0][1]=sum[0][2]=0;
        for (int i=1;i<=n;i++) 
            for (int j=1;j<=m;j++) 
                scanf("%d",&a[i][j]),sum[i][j]=sum[i-1][j]+a[i][j];
        if (m==1){
            memset(f,0,sizeof(f));
            for (int i=1;i<=n;i++) {
                f[i][0]=0;
                for (int l=1;l<=k;l++){
                    f[i][l]=f[i-1][l];
                    for (int j=0;j<i;j++){
                        f[i][l]=max(f[i][l],f[j][l-1]+sum[i][1]-sum[j][1]);
                    }
                }
            }
            printf("%d
    ",f[n][k]);
        } else {
            memset(w,0,sizeof(w));
            for (int i=1;i<=n;i++) {
                for (int j=1;j<=n;j++){
                    w[i][j][0]=0;
                    for (int l=1;l<=k;l++){
                        w[i][j][l]=max(w[i-1][j][l],w[i][j-1][l]);
                        for (int ii=0;ii<i;ii++) 
                            w[i][j][l]=max(w[i][j][l],w[ii][j][l-1]+sum[i][1]-sum[ii][1]);
                        for (int jj=0;jj<j;jj++) 
                            w[i][j][l]=max(w[i][j][l],w[i][jj][l-1]+sum[j][2]-sum[jj][2]);
                        if (i==j)
                            for (int jj=0;jj<i;jj++)
                                w[i][i][l]=max(w[i][i][l],w[jj][jj][l-1]+sum[i][1]-sum[jj][1]+sum[j][2]-sum[jj][2]);
                    }
                }       
            }
            printf("%d
    ",w[n][n][k]);
        }
        return 0;
    }
  • 相关阅读:
    C#XML创建与节点对象引用
    设计模式之四单件模式
    设计模式之三抽象工厂模式
    设计模式之二工厂方法模式
    设计模式之 一简单工厂模式
    多线程之生产者---消费者模式
    c#指针用法示例。
    序列化与反序列化实现深度复制。
    把datagrid转换成gridview
    3.sql基础
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3560067.html
Copyright © 2020-2023  润新知