题目描述
这里有一个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了呀。不过是线性区间取数的加强版。
接下来我们考虑状态,用dp[i][j][k]表示第i行,取了j个矩阵。其中k表示当前状态的一些操作:(用x表示取,o表示不取)xo(10), ox(01), xx(11), oo(00)。
考虑状态转移:以xo的情况为例:
xo ox xx oo xo xo xo xo 1 2 3 4
可是问题就来了,1、2、4状态都很好转移,但是3的转移举步维艰。为了能顺利的转移,我们再引入一个新的状态(Xx 100) 表示现在选取的两个数左右分别一个矩形,并且用原来的xx表示现在选的两个数在同一个矩形。代码就写好了(极长的状态转移):
#include<cstdio> #include<cstring> #include<algorithm> #define ox 1 #define xo 2 #define oo 0 #define xx 3 using namespace std; const int inf = 0x3f3f3f3f; int dp[105][12][4], n, m, k, mp[105][2], tmp[2][4], mx; int main() { scanf("%d%d%d", &n, &m, &k); for(register int i = 1; i <= n; ++i) for(register int j = 0; j < m; ++j) scanf("%d", &mp[i][j]); if(m == 2) { dp[1][0][oo] = dp[1][0][ox] = dp[1][0][xo] = dp[1][0][xx] = 0; dp[1][1][oo] = 0; dp[1][1][ox] = mp[1][1]; dp[1][1][xo] = mp[1][0]; dp[1][1][xx] = mp[1][1] + mp[1][0]; for(register int j = 1; j <= k; ++j) printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", 1, j, dp[1][j][oo], dp[1][j][xx], dp[1][j][xo], dp[1][j][ox]); for(register int i = 2; i <= n; ++i) { for(register int j = 1; j <= k; ++j) { if(j) { tmp[0][oo] = dp[i - 1][j - 1][oo]; tmp[0][xx] = dp[i - 1][j - 1][xx]; tmp[0][xo] = dp[i - 1][j - 1][xo]; tmp[0][ox] = dp[i - 1][j - 1][ox]; }else tmp[0][oo] = tmp[0][xx] = tmp[0][xo] = tmp[0][ox] = -inf; tmp[1][oo] = dp[i - 1][j][oo]; tmp[1][xx] = dp[i - 1][j][xx]; tmp[1][xo] = dp[i - 1][j][xo]; tmp[1][ox] = dp[i - 1][j][ox]; dp[i][j][oo] = max(max(tmp[1][oo], tmp[1][xx]), max(tmp[1][ox], tmp[1][xo])); dp[i][j][xx] = max(max(tmp[0][oo], tmp[1][xx]), max(tmp[0][ox], tmp[0][xo])) + mp[i][0] + mp[i][1]; dp[i][j][ox] = max(max(tmp[0][oo], tmp[0][xx]), max(tmp[1][ox], tmp[0][xo])) + mp[i][1]; dp[i][j][xo] = max(max(tmp[0][oo], tmp[0][xx]), max(tmp[0][ox], tmp[1][xo])) + mp[i][0]; } for(register int j = 1; j <= k; ++j) printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", i, j, dp[i][j][oo], dp[i][j][xx], dp[i][j][xo], dp[i][j][ox]); } for(register int i = 0; i <= k; ++i) mx = max(mx, max(max(dp[n][k][oo], dp[n][k][xx]), max(dp[n][k][ox], dp[n][k][xo]))); printf("%d\n", mx); return 0; } dp[1][1][xo] = mp[1][0]; for(register int i = 2; i <= n; ++i) { for(register int j = 1; j <= k; ++j) { if(j) { tmp[0][oo] = dp[i - 1][j - 1][oo]; tmp[0][xo] = dp[i - 1][j - 1][xo]; }else { tmp[0][oo] = tmp[0][xo] = -inf; } tmp[1][oo] = dp[i - 1][j][oo]; tmp[1][xo] = dp[i - 1][j][xo]; dp[i][j][oo] = max(tmp[1][oo], tmp[1][xo]); dp[i][j][xo] = max(tmp[0][oo], tmp[1][xo]) + mp[i][0]; mx = max(mx, max(dp[i][j][xo], dp[i][j][oo])); } for(register int j = 0; j <= k; ++j) printf("%d %d, oo : %d xx : %d xo : %d ox : %d\n", i, j, dp[i][j][oo], dp[i][j][xx], dp[i][j][xo], dp[i][j][ox]); } printf("%d\n", mx); return 0; }
没有帐号? 立即注册