zoukankan      html  css  js  c++  java
  • [BZOJ] 1084 [SCOI2005]最大子矩阵

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3540  Solved: 1771
    [Submit][Status][Discuss]
    Description
      这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵
    不能相互重叠。
    
    Input
      第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的
    分值的绝对值不超过32767)。
    
    Output
      只有一行为k个子矩阵分值之和最大为多少。
    
    Sample Input
    3 2 2
    
    1 -3
    
    2 3
    
    -2 3
    Sample Output
    9

    m非常非常小,一开始还以为和n一样,苦恼了半天。。
    感觉是状压,可是有这种奇怪的情况
    11
    10
    11
    10
    11
    按行扫描的状压会认为它是五个矩阵,其实四个就行,就是说我们不知道这个新点是作为原矩阵的一部分还是另成矩阵。。

    SYQ大兄弟写了巨型代码,分类讨论,很强

    数据分治一下

    m=1时,就是最大子段和问题,f[i][j][1/0]表示前i个,分了j段,且第i个选/不选的情况。

    m=2时, 用扫描的思想,f[i][j][k]表示第一列扫到第i个,第二列扫到第j个,分了k个矩阵的情况。
    转移的时候讨论列增加,或整块增加。
    用前缀和快速算增加量。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    inline int rd(){
        int ret=0,f=1;char c;
        while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
        while(isdigit(c))ret=ret*10+c-'0',c=getchar();
        return ret*f;
    }
    
    int n,m,lim;
    
    int a[105][3];
    
    int g[105][15][2];
    void solve1(){
        memset(g,0xcf,sizeof(g));
        g[0][0][0]=g[0][0][1]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=lim;j++){
                if(j)g[i][j][1]=max(g[i][lim][1],max(max(g[i-1][j-1][1],g[i-1][j-1][0]),g[i-1][j][1]))+a[i][1];
                g[i][j][0]=max(g[i-1][j][0],g[i-1][j][1]);
            }
        }
        cout<<max(g[n][lim][0],g[n][lim][1]);
    }
    
    
    int f[105][105][15];
    int sum[105][105];
    int both[105];
    void solve2(){
    //  memset(f,0xcf,sizeof(f));
    //  f[0][0][0]=0;
        for(int i=1;i<=n;i++) 
            for(int j=1;j<=m;j++)
                sum[i][j]=sum[i-1][j]+a[i][j];
        for(int i=1;i<=n;i++)
            both[i]=both[i-1]+a[i][1]+a[i][2];
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                for(int k=lim;k>=1;k--){
                    int &now = f[i][j][k];
                    now=max(f[i-1][j][k],f[i][j-1][k]);
                    for(int l=1;l<=i;l++) now=max(now,f[l-1][j][k-1]+sum[i][1]-sum[l-1][1]);
                    for(int l=1;l<=j;l++) now=max(now,f[i][l-1][k-1]+sum[j][2]-sum[l-1][2]);
                    for(int l=1;l<=min(i,j);l++) now=max(now,f[l-1][l-1][k-1]+both[min(i,j)]-both[l-1]);
                }
            }
        }
        cout<<f[n][n][lim]<<endl;
    }
    
    int main(){
        n=rd();m=rd();lim=rd();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                a[i][j]=rd();
            }
        }
        if(m==1) solve1();
        else solve2();
        return 0;
    }
    

    本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9247399.html

  • 相关阅读:
    简单说说 Java 的 JVM 内存结构
    cpu怎么实现运算的
    triplet
    LCT的一些坑【已经变成坑点集合了233】
    插头DP学习笔记
    一个坑-卡常
    NOIP2017游记
    洛谷P4015 运输问题
    线性基学习笔记
    洛谷P4331[BOI2004] sequence
  • 原文地址:https://www.cnblogs.com/ghostcai/p/9247399.html
Copyright © 2011-2022 走看看