1. 程式人生 > >前綴和----求最大子矩陣和

前綴和----求最大子矩陣和

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 }

前綴和----求最大子矩陣和