[BZOJ1084][SCOI2005]最大子矩阵

1084: [SCOI2005]最大子矩阵

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 2984  Solved: 1490
[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
 
发现最多只有两列,肯定要从这里入手
设$f[i][j][k]$表示第$1$列选了前$i$行,第$2$列选了前$j$行,一共选了$k$次的最大值
转移时考虑选或者不选,要选的话选几列
复杂度$O(n^3k)$
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char buf[10000000], *ptr = buf - 1;
inline int readint(){
    int f = 1, n = 0;
    char ch = *++ptr;
    while (ch < '0' || ch > '9'){
        if(ch == '-') f = -1;
        ch = *++ptr;
    }
    while (ch <= '9' && ch >= '0'){
        n = (n << 1) + (n << 3) + ch - '0';
        ch = *++ptr;
    }
    return f * n;
}
const int maxn = 100 + 10, INF = 0x7f7f7f7f;
int N, M, K;
int s[maxn], sum[maxn][3];
int f[maxn][11], g[maxn][maxn][11];
void work1(){
    s[0] = 0;
    for(int i = 1; i <= N; i++) s[i] = s[i - 1] + readint();
    for(int i = 0; i <= N; i++)
        for(int k = 1; k <= K; k++)
            f[i][k] = -INF;
    for(int i = 1; i <= N; i++)
        for(int k = 1; k <= K; k++){
            f[i][k] = f[i - 1][k];
            for(int j = 0; j < i; j++)
                f[i][k] = max(f[i][k], f[j][k - 1] + s[i] - s[j]);
        }
    printf("%d\n", f[N][K]);
}
void work2(){
    sum[0][1] = sum[0][2] = 0;
    for(int i = 1; i <= N; i++){
        sum[i][1] = sum[i - 1][1] + readint();
        sum[i][2] = sum[i - 1][2] + readint();
    }
    for(int i = 0; i <= N; i++)
        for(int j = 0; j <= N; j++)
            for(int k = 1; k <= K; k++)
                g[i][j][k] = -INF;    
    for(int i = 1; i <= N; i++)
        for(int j = 1; j <= N; j++)
            for(int k = 1; k <= K; k++){
                g[i][j][k] = max(g[i - 1][j][k], g[i][j - 1][k]);
                for(int L = 0; L < i; L++)
                    g[i][j][k] = max(g[i][j][k], g[L][j][k - 1] + sum[i][1] - sum[L][1]);
                for(int L = 0; L < j; L++)
                    g[i][j][k] = max(g[i][j][k], g[i][L][k - 1] + sum[j][2] - sum[L][2]);
                if(i == j)
                    for(int L = 0; L < i; L++)
                        g[i][j][k] = max(g[i][j][k], g[L][L][k - 1] + sum[i][1] + sum[i][2] - sum[L][1] - sum[L][2]);
            }
    printf("%d\n", g[N][N][K]);
}
int main(){
    fread(buf, sizeof(char), sizeof(buf), stdin);
    N = readint();
    M = readint();
    K = readint();
    if(M == 1) work1();
    else work2();
    return 0;
}

 

posted @ 2017-09-26 20:00  Elder_Giang  阅读(51)  评论(0编辑  收藏