學習材料:王知昆《淺談用極大化思想解決最大子矩陣問題》
【最大子矩陣問題】
在一個給定的矩形中有一些障礙點,找出內部不包含障礙點的、輪廓與整個矩形平行或重合的最大子矩形。
【定義子矩形】
有效子矩形:內部不包含障礙點的、輪廓與整個矩形平行或重合的子矩形。
極大子矩形:每條邊都不能向外擴展的有效子矩形。
最大子矩形:所有有效子矩形中最大的一個(或多個)。
【極大化思想】
在一個有障礙點的矩形中最大子矩形一定是極大子矩形。
設計算法的思路:枚舉所有的極大子矩形,找到最大子矩形。
設NM分別為整個矩形的長和寬,S為內部的障礙點數。
【算法1】
時間復雜度:O(S^2) 空間復雜度:O(S)
由於極大子矩形的每一條邊都不能向外擴展,那么極大子矩陣的每條邊要么覆蓋了障礙點,要么與整個矩形的邊界重合
基本算法:枚舉上下左右四個邊界,然后判斷組成的矩形是否是有效子矩形。
復雜度:O(S^5) 可以改進的地方:產生了大量的無效子矩形。
初步改進的算法:枚舉左右邊界,然后對處在邊界內的點排序,每兩個相鄰的點和左右邊界組成一個矩形。
復雜度:O(S^3) 可以改進的地方:枚舉了部分不是極大子矩形的情況。
綜上,設計算法的方向:
1、保證每一個枚舉的矩形都是有效的。
2、保證每一個枚舉的矩形都是極大的。
算法的過程:
枚舉極大子矩形的左邊界——>根據確定的左邊界,找出相關的極大子矩形——>檢查和處理遺漏的情況
(1)按照橫坐標從小到大的順序將所有的點編號為1,2,3...
(2)首先選取1號點作為要枚舉的極大子矩形的左邊界,設定上下邊界為矩形的上下邊界
(3)從左到右掃描,第一次到2號點,確定一個極大子矩形,修改上下邊界;第二次找到3號點,以此類推。
(4)將左邊界移動到2號點,3號點,,,以同樣的方法枚舉
遺漏的情況:
1、矩形的左邊界與整個矩形的左邊界重合。解決方法:用類似的方法從左到右掃一遍
2、矩形的左邊界與整個矩形的左邊界重合,且矩形的右邊界與整個矩形的右邊界重合。解決方法:預處理時增加特殊判斷。
優點:利用的極大化思想,復雜度可以接受,編程實現簡單。
缺點:使用有一定的局限性,不適合障礙點較密集的情況。
【算法2】
時間復雜度O(NM) 空間復雜度O(NM)
定義
有效豎線:除了兩個端點外,不覆蓋任何一個障礙點的豎直線段。
懸線:上端覆蓋了一個障礙點或者到達整個矩形上邊界的有效線段。
每個懸線都與它底部的點一一對應,矩形中的每一個點(矩形頂部的點除外)都對應了一個懸線。
懸線的個數=(N-1)*M;
如果把一個極大子矩形按照橫坐標的不同切割成多個與y軸平行的線段,那么其中至少有一個懸線。
如果把一個懸線向左右兩個方向盡可能的移動,那么就得到了一個矩形,我們稱它為懸線對應的矩形。
懸線對應的矩形不一定是極大子矩形,因為下邊界可能還可以向下擴展。
設計算法:
具體方法:
代碼實現具體見WC2002 奶牛浴場(算法1)
codevs1159最大全0子矩陣(算法2)
補圖:
算法1:
s為障礙點總數。
枚舉一個障礙點作為左邊界O(s),然后不斷向后掃得到極大子矩形O(s),總復雜度為O(s^2)。
當1障礙點數較小時,可以使用算法1。
算法2(懸線法):
當障礙點較多,n*m較小時,可以用懸線法。
時間復雜度為O(n*m)。
例題:bzoj1057
猴似猴塞雷~~
2016-08-19 15:02:38