luogu 2331 [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
分析
方法1
O(n3*k):luogu 2331 题解
这题中,空矩阵也算子矩阵
m == 1时dp[前i列][选了j个矩阵],分为选与不选当前格两种,选的时候可以连着前面的当做一个矩阵
m == 2 的做法类比m == 1的做法,
f[第1列选了前i个][第2列选了前j个][选了k个子矩阵] = 最大和
对于当前的要选的子矩阵,选的情况有4种:
1. 不选
2. 选第一列
3.选第二列
3.i==j时两列可以看做一个矩阵
代码:
1 /*********************** 2 User:Mandy.H.Y 3 Language:c++ 4 Problem: 5 Algorithm: 6 ***********************/ 7 8 #include<bits/stdc++.h> 9 10 using namespace std; 11 12 const int maxn = 105; 13 14 int n,m,K; 15 int a[105][5]; 16 int sum[105][5]; 17 int dp[maxn][15]; 18 int f[maxn][maxn][15]; 19 20 template<class T>inline void read(T &x){ 21 x = 0;bool flag = 0;char ch = getchar(); 22 while(!isdigit(ch)) flag |= ch == '-',ch = getchar(); 23 while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar(); 24 if(flag) x = -x; 25 } 26 27 template<class T>void putch(const T x){ 28 if(x > 9) putch(x / 10); 29 putchar(x % 10 | 48); 30 } 31 32 template<class T>void put(const T x){ 33 if(x < 0) putchar('-'),putch(-x); 34 else putch(x); 35 } 36 37 void file(){ 38 freopen("2331","r",stdin); 39 } 40 41 void readdata(){ 42 read(n);read(m);read(K); 43 for(int i = 1;i <= n; ++ i){ 44 for(int j = 1;j <= m; ++ j){ 45 read(a[i][j]); 46 sum[i][j] = sum[i - 1][j] + a[i][j]; 47 } 48 } 49 } 50 51 void work(){ 52 if(m == 1){//其实这样没必要,因为可以当m == 2做只是第二列等于0; 53 for(int i = 1;i <= n; ++ i) 54 for(int j = 1;j <= K; ++ j){ 55 dp[i][j] = dp[i-1][j];//不选 56 for(int l = 0;l <= i; ++ l)//l可以等于i,空矩阵也算子矩阵 57 dp[i][j] = max(dp[i][j],dp[l][j-1] + sum[i][1] - sum[l][1]); 58 } 59 put(dp[n][K]); 60 } else { 61 for(int i = 1;i <= n; ++ i) 62 for(int j = 1;j <= n; ++ j) 63 for(int k = 1;k <= K; ++ k){ 64 f[i][j][k] = max(f[i-1][j][k],f[i][j-1][k]);//不选 65 for(int l = 0;l <= i; ++ l)//选第一列 66 f[i][j][k] = max(f[i][j][k],f[l][j][k-1] + 67 sum[i][1] - sum[l][1]); 68 69 for(int l = 0;l <= j;++ l)//选第二列 70 f[i][j][k] = max(f[i][j][k],f[i][l][k-1] + 71 sum[j][2] - sum[l][2]); 72 73 if(i == j) 74 for(int l = 0;l <= i; ++ l)//两列一起 75 f[i][j][k] = max(f[i][j][k],f[l][l][k-1] + 76 sum[i][1] - sum[l][1] + 77 sum[j][2] - sum[l][2]); 78 } 79 put(f[n][n][K]); 80 } 81 } 82 83 int main(){ 84 // file(); 85 readdata(); 86 work(); 87 return 0; 88 }
非做顽石不可,哪管他敬仰暗唾