連接:http://noi.openjudge.cn/ch0406/1768/spa
描述
已知矩陣的大小定義爲矩陣中全部元素的和。給定一個矩陣,你的任務是找到最大的非空(大小至少是1 * 1)子矩陣。3d
好比,以下4 * 4的矩陣code
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2blog
的最大子矩陣是it
9 2
-4 1
-1 8io
這個子矩陣的大小是15。
輸入
輸入是一個N * N的矩陣。輸入的第一行給出N (0 < N <= 100)。再後面的若干行中,依次(首先從左到右給出第一行的N個整數,再從左到右給出第二行的N個整數……)給出矩陣中的N2個整數,整數之間由空白字符分隔(空格或者空行)。已知矩陣中整數的範圍都在[-127, 127]。
輸出
輸出最大子矩陣的大小。
樣例輸入
4
0 -2 -7 0 9 2 -6 2
-4 1 -4 1 -1class
8 0 -2
樣例輸出
15循環
芒果君:第一次看到這道題,仍是在貪內心,就特別懵逼,後來dalao教我用矩陣前綴和來寫,畫個圖的話就很容易理解啦~im
(a:元素,sum:從a(1,1)到a(i,j)全部值的和,就是前綴和。)img
邊讀入邊求前綴和(sum),用這個公式來求:①+②+③-④ 得出sum(5,3)=a(5,3)+sum(4,2)+sum(5,2)-sum(4,2);
好像有點遞推思想呢?
而後四重循環暴力枚舉全部子矩陣,找到最大值!
公式:①-②-③+④,枚舉出(2,2)到(5,3)的矩陣大小t=sum(5,3)-sum(5,1)-sum(1,3)+sum(1,1),更新最大值。代碼以下——
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int ju[110][110],sum[110][110],n,i,j,k,l,ans; 5 int main() 6 { 7 scanf("%d",&n); 8 for(i=1;i<=n;++i) 9 for(j=1;j<=n;++j){ 10 scanf("%d",&ju[i][j]); 11 sum[i][j]=ju[i][j]+sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; 12 } 13 for(i=1;i<=n;++i) 14 for(j=1;j<=n;++j) 15 for(k=1;k<=i;++k) 16 for(l=1;l<=j;++l) 17 ans=max(ans,sum[i][j]+sum[k-1][l-1]-sum[i][l-1]-sum[k-1][j]); 18 printf("%d",ans); 19 return 0; 20 }
而後呢,這道題用DP作就是醬紫的(參考最大子序列和)~讀入的時候求每一列的前綴和,再用三重循環把它處理成子矩陣(i,j限制行的範圍,k是列)。抽象的看,是由線到面的轉化。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int ju[110][110],f[110],n,i,j,k,ans; 5 int main() 6 { 7 scanf("%d",&n); 8 for(i=1;i<=n;++i) 9 for(j=1;j<=n;++j){ 10 scanf("%d",&ju[i][j]); 11 ju[i][j]+=ju[i-1][j]; 12 } 13 for(i=1;i<=n;++i) 14 for(j=1;j<i;++j){ 15 for(k=1;k<=n;++k) 16 f[k]=ju[i][k]-ju[j][k]; 17 for(k=1;k<=n;++k){ 18 f[k]=max(f[k],f[k-1]+f[k]); 19 ans=max(ans,f[k]); 20 } 21 } 22 printf("%d",ans); 23 return 0; 24 }
各位dalao看懂了嗎?沒看懂也不關個人事~
(最後不負責任的博主在一片罵聲中點下了保存修改)