題目的Link在這裡:ACM UVa 108 - Maximum Sum
UVa 507和108其實是相關的。507是可以看作是一維的Maximum Interval Sum問題,而本題則是
任何一個n*m的Rectangle:
a11 a12 ... a1n
a21 a22 ... a2n
.....................
am1 am2 ... amn
可以看作一個一維的數組,其值為:( (a11+a12+...+a1n), (a21+a22+...+a2n), ..., (am1+am2+...+amn) )
於是求該Rectangle中最大n*k的Sub-Rectangle可以通過求該變換過的一維數組中的最大連續序列獲得。注意求得的結果是n*k的。那麼,對於二維數組中的每一行都可以有(1+n)*n/2種子序列,比如
a1,
a1, a2
a1, a2, ... an
a2,
a2, a3,
a2, a3, ... an
...
an-1, an
an
通過對每一個這樣的子序列求和,正如上面所說,可以把2維問題轉化為1維問題。
那麼最終的演算法的複雜度是多少呢?直覺上,求每行的i...j的子序列需要O(n^3)的複雜度(3層迴圈,一層i,一層j,一層從i+到j)再加上一維的從左往右的Scan共是O(n^4)。其實,求每行i..j的子序列不需要O(n^3),注意到從i...j-1到i...j中間相差一個元素,因此可以通過利用上一次的計算的結果來累加的方式獲得,所以只需要O(n^2)就可以做到。於是最後的複雜度為O(n^3)。
代碼如下:
//
// ACM UVa Problem #108
// http://acm.uva.es/p/v1/108.html
//
// Author: ATField
// Email: atfield_zhang@hotmail.com
//
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
using namespace std;
#define MAX 105
int main(int argc, char *argv[])
...{
int n;
cin >> n;
char r[MAX][MAX];
for( int i = 0; i < n; ++i )
for( int j = 0; j < n; ++j )
...{
int num;
cin >> num;
r[i][j] = (char)num;
}
//
// find max sub rectangle
//
int max = r[0][0];
int max_column = 0;
int max_span = 0;
int max_row_start = 0;
int max_row_end = 0;
int sum[MAX];
for( int column = 0; column < n; ++column)
...{
for( int row = 0; row < n; ++row )
sum[row] = 0;
for( int span = 0; span < n - column; ++span )
...{
int current = 0;
int left = 0;
for( int row = 0; row < n; ++row )
sum[row] = sum[row] + r[row][column + span];
for( int i = 0; i < n; ++i )
...{
if( current < 0 )
...{
left = i;
current = 0;
}
current += sum[i];
if( current > max )
...{
max = current;
max_row_start = left;
max_row_end = i;
max_column = column;
max_span = span;
}
}
}
}
cout << max;
return 0;
}
二維的Maximum Interval Sum問題,可以建立在一維的基礎上面解決。