後來查了很多資料,看人家的想法等等。
才發現到,原來Maximum subarray problem,
已經有人在研究。一維list,可以用O(n)就找出max sum。
這個方法稱為Kadane's algorithm。
而二維套用一維的概念,就可以花O(n ^ 3)的時間找出max sum。
解法主要參考這裡。
另外要講一下,algorithmist的解法應該是正確的,
但是prefix sum應該會花O(n ^ 3)的時間建立。我覺得algorithmist寫得太簡略,
以至於讓人看不懂(或是誤解)。
主要想法:對於一維陣列,
我們可以使用Kadane's algorithm以O(n)的方式求出max sum。
所以二維陣列,可以用一維陣列的方式求解。
例如題目給的陣列
0 -2 -7 0 (1)
9 2 -6 2 (2)
-4 1 -4 1 (3)
-1 8 0 -2 (4)
其實可以看成10個子陣列(皆一維)
這些陣列分別是
(1)、(1) + (2)、(1) + (2) + (3)、(1) + (2) + (3) + (4)、
(2)、(2) + (3)、(2) + (3) + (4)、
(3)、(3) + (4)、
(4)。
從這十個一維陣列中找出max sum,即是答案。
建立子陣列需要花O(n ^ 2)的時間,而每個陣列需要花O(n)的時間找sum。
所以總共要花O(n ^ 3)的時間。
Kadane's algorithm滿像我解ACM661找最大電流的方法,
不過Kadane's algorithm更精確……令人佩服!
Kadane's algorithm的說明可以看wiki python實作,
或是Algorithm的code實作,
可以一目了然其運作原理。
這裡也有解釋Kadane's algorithm。
(但不要看他的code,是錯的……雖然AC)
uva toolkit的output也是錯的……。
/* ACM 108 Maximum Sum * mythnc * 2011/10/28 21:31:21 * run time: 0.008 */ #include <stdio.h> #include <string.h> #define MAXN 100 void subsum(int, int); int s[MAXN][MAXN]; int colsum[MAXN]; int max; int main(void) { int n, i, j; scanf("%d", &n); /* init */ for (i = 0; i < n; i++) for (j = 0; j < n; j++) scanf("%d", &s[i][j]); max = -12701; for (i = 0; i < n; i++) { for (j = i; j < n; j++) subsum(j, n); /* clear colsum's content */ memset(colsum, 0, sizeof(int) * n); } printf("%d\n", max); return 0; } /* subsum: calculate the sub-rectangle value */ void subsum(int row, int n) { int i, j, sum; for (i = 0; i < n; i++) colsum[i] += s[row][i]; /* Kadane's algorithm (modified) */ for (i = sum = 0; i < n; i++) { sum += colsum[i]; if (sum > max) max = sum; if (sum < 0) sum = 0; } }
1 則留言:
原文 :
其實可以看成10個子陣列(皆一維)
這些陣列分別是
(1)、(1) + (2)、(1) + (2) + (3)、(1) + (2) + (3) + (4)、
(2)、(2) + (3)、(2) + (3) + (4)、
(3)、(3) + (4)、
(4)。
---------------------------------
一開始看到這幾句話我以為是要把二維陣列轉為一維陣列再去處理
但是後來實作發現還是維持二維陣列
但是改為一次看多個column去計算
比方說
0 -2 -7 0 (1)
9 2 -6 2 (2)
計算max sum時是看 (0+9) , (-2+2) , (-7-6) , (0+2) 裡面的連續最大值
張貼留言