【題目描述】
已知矩陣的大小定義爲矩陣中所有元素的和。給定一個矩陣,你的任務是找到最大的非空(大小至少是1 × 1)子矩陣。
比如,如下4 × 4的矩陣
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
的最大子矩陣是
9 2
-4 1
-1 8
這個子矩陣的大小是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
-1 8 0 -2
【輸出樣例】
15
————————————————
思路:假設所求N*N的矩陣的最大子矩陣是從i列到j列,q行到p行,如下圖所示
a[1][1] a[1][2] ······ a[1][i] ······ a[1][j] ······ a[1][n]
a[2][1] a[2][2] ······ a[2][i] ······ a[2][j] ······ a[2][n]
······
a[q][1] a[q][2] ······ a[q][i] ······ a[q][j] ······ a[q][n]
······
a[p][1] a[p][2] ······ a[p][i] ······ a[p][j] ······ a[p][n]
······
a[n][1] a[n][2] ······ a[n][i] ······ a[n][j] ······ a[n][n]
最大子矩陣就是圖示劃線部分,如果把最大子矩陣同列的加起來,我們可以得到一個一維數組{a[q][i]+······+a[p][i] , ······ ,a[q][j]+······+a[p][j] } ,現在我們可以看出,這其實就是一個一維數組的最大子段問題。即把二維數組看成是縱向的一維數組和橫向的一維數組。
想找到n個數的最大子段和,先要找到n-1個數的最大子段和。我們用sum來表示t[0]…t[i]的最大子段和,sum有兩種情況:(1)最大子段一直到t[i] (2)以t[i]爲首的新的子段。可以得到sum的狀態轉移方程:sum=max{sum+t[i],t[i]}。最終我們得到的最大子段和爲max{sum, 0<=i<n}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
#define N 1001
using namespace std;
int a[N][N],f[N];
int maxArray(int t[],int n)
{
int sum = 0,maxx = -INF;
for(int i = 1;i <= n;i++)
{
if(sum > 0)
sum += t[i];//若t[i]+sum[i-1]會減小
else
sum = t[i];// 則以t[i]爲首另起一個子段
if(sum > maxx)
maxx = sum;
}
return maxx;
}
int main()
{
int n;
cin >> n;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= n;j++)
cin >> a[i][j];
int maxx = -INF;
for(int i = 1;i <= n;i++)
{
memset(f,0,sizeof(f));
for(int j = i;j <= n;j++)
{
for(int k = 1;k <= n;k++)
f[k] += a[j][k];
int temp = maxArray(f,n);
if(temp > maxx)
maxx = temp;
}
}
cout << maxx << endl;
return 0;
}