前綴和----求最大子矩陣和
阿新 • • 發佈:2019-04-24
span www sca 貪心 mda 就是 can 它的 for
本文部分借鑒源於大佬的博客:http://www.cnblogs.com/mrclr/p/8423136.html%20
現在有一個問題,有一個一維數組,求它的最大區間和。
我們可以利用貪心的思想,先將這個數組前綴和處理,所以我們可以得到區間和為 sum[L—R] = sum[R] - sum[L-1];因此,我們可以一邊枚舉R一邊去找最小值,取這個區間和去和答案判斷找到最大區間和。
1 int FindSum() 2 { 3 int maxn = 0; 4 int minst = inf; 5 for (int i = 1; i <= n; i++) 6 { 7 minst = min(minst, sum[i - 1]); 8 maxn = max(maxn, sum[i] - minst); 9 } 10 return maxn; 11 }
我們現在去求二維矩陣的最大子矩陣和。
我們先將矩陣進行預處理,將它的每個列存到一個前綴和二維數組f[i][j]裏,這樣的話我們只需要枚舉起始和終止的行,在這個區間去進行降維為一維去求最大和就可以將時間復雜度變為O(n^3)。
像上圖,我們只需要將i-j之間的矩陣降維到一維,(具體操作是你之前預處理列的前綴和數組f[i-j][k]=f[j][k]-f[i-1][k] ,將f數組降維到一維,求最大區間和),便求出了最大矩陣和。
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 const int maxn = 4e2 + 5; 8 const int INF = 0x3f3f3f3f; 9 int n, ans = -INF; 10 int a[maxn][maxn], f[maxn][maxn]; //f[i][j]關於第j列到第i行的列前綴和11 void init(const int& n) 12 { 13 for(int i = 1; i <= n; ++i) 14 for(int j = 1; j <= n; ++j) 15 f[i][j] = f[i - 1][j] + a[i][j]; //求一列的和 16 } 17 int b[maxn], sum[maxn]; //降維後的數組 18 int main() 19 { 20 scanf("%d", &n); 21 for(int i = 1; i <= n; ++i) 22 for(int j = 1; j <= n; ++j) 23 scanf("%d", &a[i][j]); 24 init(n); 25 for(int i = 1; i <= n; ++i) 26 for(int j = i; j <= n; ++j) 27 { 28 for(int k = 1; k <= n; ++k) b[k] = f[j][k] - f[i - 1][k]; //降維 29 for(int k = 1; k <= n; ++k) sum[k] = sum[k - 1] + b[k]; //求一維前綴和 30 int Min = INF; 31 for(int k = 1; k <= n; ++k) 32 { 33 Min = min(Min, sum[k - 1]); 34 ans = max(ans, sum[k] - Min); 35 } 36 } 37 printf("%d\n", ans); 38 return 0; 39 }
我們現在看一道例題hdu1559。
題目大意:
給你一個m×n的整數矩陣,在上面找一個x×y的子矩陣,使子矩陣中所有元素的和最大。這道題n,m<1000,所以我們考慮一下我們只要求固定的子矩陣x,y。
我們只要枚舉矩陣起始行,結束行也就是i+x,在進行降維找到最大子矩陣和就ok了,這樣的時間復雜度也降到了O(n^2),是不是很簡單。
1 #include <iostream> 2 #include <stack> 3 #include <stdio.h> 4 #include <cstdio> 5 #include <cstring> 6 using namespace std; 7 #define maxx 110000 8 typedef long long ll; 9 const int inf = 0x3f3f3f3f; 10 int a[1010][1010]; 11 int sum[1010]; 12 int f[1010][1010]; 13 int b[1010]; 14 int n, m; 15 16 void init() 17 { 18 for (int i = 1; i <= n; i++) 19 { 20 for (int j = 1; j <= m; j++) 21 { 22 f[i][j] = f[i - 1][j] + a[i][j]; 23 } 24 } 25 } 26 27 int main() 28 { 29 int T; 30 cin >> T; 31 while (T--) 32 { 33 memset(f, 0, sizeof(f)); 34 int x, y; 35 cin >> n >> m >> x >> y; 36 for (int i = 1; i <= n; i++) 37 { 38 for (int j = 1; j <= m; j++) 39 { 40 cin >> a[i][j]; 41 } 42 } 43 init(); 44 int maxn = 0; 45 for (int i = 1; i <= n; i++) 46 { 47 memset(sum, 0, sizeof(sum)); 48 memset(b, 0, sizeof(b)); 49 int j = i + x - 1; 50 for (int k = 1; k <= m; k++) 51 b[k] = f[j][k] - f[i - 1][k]; 52 for (int k = 1; k <= m; k++) 53 sum[k] = sum[k - 1] + b[k]; 54 for (int k = 1; k + y <= m + 1; k++) 55 { 56 maxn = max(maxn, sum[k + y - 1] - sum[k - 1]); 57 } 58 } 59 cout << maxn << endl; 60 } 61 return 0; 62 }
前綴和----求最大子矩陣和