例題:奶牛沐場
最大子矩陣面積,怎麼求呢?
可以想到的是,這個矩陣一定是極大子矩陣。(什麼?你不知道什麼是極大子矩陣?百度吧。。。)
然後怎麼求呢?
這個子矩陣每一條邊都不可以伸展了,也就是說他的邊界上一定有障礙點或者是與邊界重合了。
算法一:
直接想到的是,上下左右枚舉四個邊界,再看看是不是滿足條件。
複雜度?
原因是什麼?我們枚舉了很多沒有用的矩陣。
很明顯,我們不可以使用這個算法。
算法二
那麼,我們可不可以優化一下?
我們只枚舉左右邊界,然後對範圍內的點排序。每兩個相鄰的點加上左右邊界就是目前的矩陣。
複雜度?
還是過不了啊。。。
原因何在?畢竟還是有很多的矩陣不是極大子矩陣。
說了這麼多,本質上都沒有用到極大子矩陣這個性質。現在我們就要用用了。
想想怎麼優化。
我們要保證以下幾點:
所有枚舉的矩陣都是有效的。
所有枚舉的矩陣都是極大的。
算法三
首先我們把點從左到右標號。爲了方便處理,我們把整個矩陣的四個角都變成障礙點。
然後把點從左到右排序。
第一次取1號點作爲左邊界,暫定整個矩陣的上下邊界是目前上下邊界。然後從左往右掃,遇到一個點,就修改上下邊界。這樣我們就得到所有的以1號點爲左邊界的極大有效子矩陣。
然後再是2號點,3號點……一直到(n−1)號點。
但是這樣不完整。
爲什麼?還有右邊界啊,你怎麼保證右邊界也這樣呢?
所以按照同樣的道理從右向左再來一次。
當然,如果左右邊界不是排序後的第一個點的橫座標而是整個矩形的邊界,那就需要特判了。
複雜度?
這就可以接受了。
但是,如過障礙點太密集,這個算法就不太優了。
算法四
考慮懸線法
什麼是懸線?我們引進“有效豎線”。
有效豎線就是除了兩個端點,不覆蓋任何障礙點的豎線段。
於是,懸線就是上端點是一個障礙點或者是上端點是整個矩陣的邊界的有效豎線。
這樣的懸線有
如果把一個極大子矩陣按照橫座標切成一條一條的,那麼其中至少有一個懸線。
我們把一根懸線左右亂移動到儘可能最偏,這樣左右邊界就確定了。
還有上下邊界
考慮點
如果點i-1是障礙點,那麼高度是1
如果不是,那麼就是上一個高度+1。
這樣就確定矩陣了。
複雜度?
也很清真啊,關鍵是不受到障礙點個數的影響。
當然,障礙點少的話,離散化一下也很好。