题目描述
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
输入格式:
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出格式:
只有一行为k个子矩阵分值之和最大为多少。
Analysis
仔细阅读题目后我们发现
1≤m≤2
1
≤
m
≤
2
这说明什么?我们可以把它强行拆分成两条链来做,于是乎题目变成在序列中取出k组数的最大值
设
f[i][j]
f
[
i
]
[
j
]
表示前i项分j组的最大值,那么
f[i][j]=f[k][j]+sum[k+1][j] (1≤k≤i)
f
[
i
]
[
j
]
=
f
[
k
]
[
j
]
+
s
u
m
[
k
+
1
]
[
j
]
(
1
≤
k
≤
i
)
二维的可以自己想一下,不难的
我会说我根本没有写判断直接就A了?
Code
#include <stdio.h>
#include <string.h>
#define rep(i, a, b) for (int i = a; i <= b; i ++)
#define fill(x, t) memset(x, t , sizeof(x))
#define N 101
#define K 11
using namespace std;
int f[N][N][K], num[N][3], s[N][3];
inline int read(){
int x = 0, v = 1;
char ch = getchar();
while (ch < '0' || ch > '9'){
if (ch == '-'){
v = -1;
}
ch = getchar();
}
while (ch <= '9' && ch >= '0'){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return x * v;
}
inline int max(int x, int y){
return x<y?y:x;
}
inline int min(int x, int y){
return x<y?x:y;
}
inline int sum(int x, int y, int v){
int tmp1 = s[y][1] - s[x - 1][1];
int tmp2 = s[y][2] - s[x - 1][2];
if (v == 1){
return tmp1;
}else if (v == 2){
return tmp2;
}else{
return tmp1 + tmp2;
}
}
int main(void){
int n = read(), m = read(), p = read();
rep(i, 1, n){
rep(j, 1, m){
num[i][j] = read();
s[i][j] = s[i - 1][j] + num[i][j];
}
}
rep(i, 1, n){
rep(j, 1, n){
rep(k, 1, p){
f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);
rep(l, 1, i){
f[i][j][k] = max(f[i][j][k], f[l - 1][j][k - 1] + sum(l, i, 1));
}
rep(l, 1, j){
f[i][j][k] = max(f[i][j][k], f[i][l - 1][k - 1] + sum(l, j, 2));
}
rep(l, 1, min(i, j)){
f[i][j][k] = max(f[i][j][k], f[l - 1][l - 1][k - 1] + sum(l, min(i, j), 3));
}
}
}
}
printf("%d\n", max(f[n][n][p], max(f[n][n][p], f[n][n][p])));
return 0;
}