[SCOI2005]最大子矩陣
阿新 • • 發佈:2017-10-13
一行 turn iostream stream 最大子矩陣 情況 span 前綴和 ()
題目描述
這裏有一個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]最大子矩陣