[SCOI2005]最大子矩阵
Posted fastle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SCOI2005]最大子矩阵相关的知识,希望对你有一定的参考价值。
题目描述
这里有一个n*m的矩阵,请你选出其中k个子矩阵,使得这个k个子矩阵分值之和最大。注意:选出的k个子矩阵不能相互重叠。
输入输出格式
输入格式:
第一行为n,m,k(1≤n≤100,1≤m≤2,1≤k≤10),接下来n行描述矩阵每行中的每个元素的分值(每个元素的分值的绝对值不超过32767)。
输出格式:
只有一行为k个子矩阵分值之和最大为多少。
输入输出样例
输入样例#1:
3 2 2 1 -3 2 3 -2 3
输出样例#1:
9
解析:
刚开始看并没有思路,直到看到了数据范围 m <= 2好吧
最多也就是两行的矩阵
这样的话我们可以暴力手模一下情况,就可以看出转移有那种情况
dp[i][j][k] 表示第一行选取到了第i个,第二行选取了第j个,选取了k个矩形的最大取值
之后分析一下
dp[i ][j][k]可以由哪些情况转移来呢
1.啥都不拿-.- 继承父辈的衣钵 在 dp[i - 1 ][j][k] 和dp[i][j - 1][k] 中去较大值
2.拿第一列的,枚举一下从哪里开始拿,
3.拿第二列的,枚举一下从哪里开始拿
4.拿两列的,枚举一下从哪里开始拿
然后涉及大量求和
前缀和优化
代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; int note[101][3]; int sum1[101]; int sum2[101]; int sum12[101]; int dp[101][101][15]; int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i = 1;i <= n;i++) { for(int j = 1;j <= m;j++) { scanf("%d",¬e[i][j]); } sum1[i] = sum1[i - 1] + note[i][1]; sum2[i] = sum2[i - 1] + note[i][2]; sum12[i] = sum12[i - 1] + note[i][1] + note[i][2]; } for(int i = 1;i <= n;i++) for(int j = 1;j <= n;j++) { for(int z = k;z >= 1;z--) { dp[i][j][z] = max(dp[i - 1][j][z],dp[i][j - 1][z]);// 第一种 for(int op = 1;op <= i;op++) dp[i][j][z] = max(dp[i][j][z],dp[op - 1][j][z - 1] + sum1[i] - sum1[op - 1]);//第二种 for(int op = 1;op <= j;op++) dp[i][j][z] = max(dp[i][j][z],dp[i][op - 1][z - 1] + sum2[j] - sum2[op - 1]);//第三种 for(int op = 1;op <= min(i,j);op++) dp[i][j][z] = max(dp[i][j][z],dp[op - 1][op - 1][z - 1] + sum12[min(i,j)] - sum12[op - 1]);//第四种 } } printf("%d",dp[n][n][k]); return 0; }
以上是关于[SCOI2005]最大子矩阵的主要内容,如果未能解决你的问题,请参考以下文章