[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;
}
發佈了180 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章