標籤:
描述
給定一個由整數組成二維矩陣(r*c),現在需要找出它的一個子矩陣,使得這個子矩陣內的所有元素之和最大,並把這個子矩陣稱為最大子矩陣。 例子:0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 其最大子矩陣為:9 2 -4 1 -1 8 其元素總和為15。
-
輸入
-
第一行輸入一個整數n(0<n<=100),表示有n組測試資料;每組測試資料:第一行有兩個的整數r,c(0<r,c<=100),r、c分別代表矩陣的行和列;隨後有r行,每行有c個整數;
-
輸出
-
輸出矩陣的最大子矩陣的元素之和。
-
範例輸入
-
14 40 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
-
範例輸出
-
15
這個問題就是最大值子區間和的二維問題。
最大子區間和是說給你一個數組,然後讓你找一個連續的子區間,讓這個區間的數的和最大。很經典的簡單DP。題目可以參考這個連結:http://acm.nyist.net/JudgeOnline/problem.php?pid=44。
一維問題的解決思路是,max_sum表示從第一數到目前的最大和,sum是某段區間的和,如果sum<0,那麼sum沒有利用價值了,把sum=0,否則就繼續往上加。
max_sum=max((sum+=a[i])<0?0:sum,max_sum);
二維的問題,其實可以轉化為一位的問題。
首先我們要注意到二維子矩陣在選取的時候是個矩陣,聯絡一個我們經常會用到的技巧:但我們需要頻繁計算一個資料任意一個區間
的和的時候,我們會預先把這個數組使用啊a[i]=a[i]+a[i-1]的方式把它記錄的值變為數組到這個位置的和,這樣的好處就是任意一個區間[i,j]的和就可轉化為了a[i]-a[j-1]。
在這裡我們依然採用這樣的技巧。我們把這個矩陣記錄的值對於每個列向量都做上述改變。
然後我們就發現,但我們選取任意的連續行進行組合的時候,這個行區間對於的列的值的和都可以用上述方法快速獲得,那麼對於每個列的和又會變為一個求一維連續區間最大和問題了。到此這個問題就可以以O(n^2)的複雜度解決了。
AC代碼:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define N 106 6 #define inf 1<<26 7 int n,m; 8 int mp[N][N]; 9 int main()10 {11 int t;12 scanf("%d",&t);13 while(t--){14 memset(mp,0,sizeof(mp));15 scanf("%d%d",&n,&m);16 for(int i=1;i<=n;i++){17 for(int j=1;j<=m;j++){18 scanf("%d",&mp[i][j]);19 mp[i][j]+=mp[i-1][j];20 }21 }22 23 int MAX = -inf;24 for(int i=1;i<=n;i++){25 for(int j=i;j<=n;j++){26 int tmp = 0;27 for(int k=1;k<=m;k++){28 int cnt = mp[j][k]-mp[i-1][k];29 tmp+=cnt;30 if(tmp>MAX) MAX = tmp;31 if(tmp<0) tmp=0;32 }33 }34 }35 printf("%d\n",MAX);36 37 }38 return 0;39 }
nyoj 104 最大和 (二維最大字串和)