最大全0子矩陣問題

2021-07-26 06:12:29 字數 1730 閱讀 5722

題意:給定乙個01矩陣,求:

1.最大全0正方形面積

2.最大全0子矩陣面積

-----------------------------------------我是分割線-----------------------------------------

對於第一問,我們有o(nm)的動態規劃解法:

設f[i][j]表示以i,j為右下角的最大正方形邊長

正確性可以自己yy一下

對於第二問有許多o(nm)的奇怪解法,具體可以參照2023年福州第三中學王知昆的**《**用極大化思想解決最大子矩陣問題》。

我只會懸線法,還有二維單調棧解法orz

令h[i][j]表示點(i,j)向上最大延伸高度,可以想象為一根在(i,j-h[i][j]+1)到(i,j)的一根懸線,可以證明,最大子矩陣是某一根懸線的向左右盡量擴張而形成的

令l[i][j]表示i,j懸線向左最大擴充的位置,r[i][j]表示i,j懸線向右最大擴充的位置,那麼max(h[i][j]*(r[i][j]-l[i][j]+1))就是答案。

現在我們要做到o(nm)處理出h,l,r陣列

h陣列顯然可以簡單遞推。

關於l[i][j],設其初值為j,考慮能否擴張到j-1及其擴張範圍,顯然如果h[i][j]<=h[i][j-1]則可以,否則不行,如果可以那麼l[i][j]=l[i][l[i][j-1]],否則就此停止;

現在考慮能否再次擴張,再進行比較h值,將之前的j-1換成l[i][j]-1即可

r陣列同理。

為什麼這個遞推是o(nm)的呢?

顯然行與行無關,我們只考慮一行內;

把l陣列看成樹結構,則l的指向即為連向父節點的邊;

如果擴張一次完成,則新節點(j)的深度為(j-1)深度+1,這種事件出現次數<=m

每次擴張的比較過程如果成功,則深度會至少減少1,每次減少深度事件複雜度為o(1)

深度減少事件發生次數<=深度++次數<=m

所以每行內遞推複雜度為o(m)

總複雜度o(nm)徵畢。

至此,整個問題解決。

因為行與行無關,l與r可以只記錄本行內,而h陣列可以用滾動陣列,故只需開一維即可,意義不變。

**:

#includeusing namespace std;

const int maxn = 2017;

int a[maxn][maxn];

int h[maxn],l[maxn],r[maxn];

int n,ans;

int main()

for(int j=n;j>=1;j--)

{ r[j]=j;

while(r[j]

1159 最大全0子矩陣

f i,j 表示以 i,j 為右下角的最大全0子矩陣的邊長 若a i j 1,f i,j 0 否則 f i,j min 1 這樣求得的是最大全0正方形子矩陣 要求長方形矩陣,上述思路行不通 假設以 i,j 為右下角的最大矩陣 12 它可能是3 4 4 3 2 6 6 2 1 12 12 1 按上述思...

codevs 1159 最大全0子矩陣

時間限制 1 s 空間限制 128000 kb 題目描述 description 在乙個0,1方陣中找出其中最大的全0子矩陣,所謂最大是指o的個數最多。輸入描述 input description 輸入檔案第一行為整數n,其中1 n 2000,為方陣的大小,緊接著n行每行均有n個0或1,相鄰兩數間嚴...

codevs1159 最大全0子矩陣

題目描述 description 在乙個0,1方陣中找出其中最大的全0子矩陣,所謂最大是指o的個數最多。輸入描述 input description 輸入檔案第一行為整數n,其中1 n 2000,為方陣的大小,緊接著n行每行均有n個0或1,相鄰兩數間嚴格用乙個空格隔開。輸出描述 output des...