作用:O(n^2)用來解決最大矩陣和問題
思路:對於 m*n 矩陣中的任意一點,覆蓋這個點的最大矩形的面積為,該點向左右最大能延伸的長度之和與向上最大能延伸的長度的乘積。
描述:首先 O(n^2) 預處理,對於矩陣上的每一個點,我們可以:
1.從它向上引一條懸線,遇到邊界或障礙點停止,h[i][j] 數組記錄從點 (i,j) 向上的懸線長度。
2.向左延伸,遇到邊界或障礙點停止,l[i][j] 數組記錄從點 (i,j) 向左最大能延伸的長度。
3.向右延伸,遇到邊界或障礙點停止,r[i][j] 數組記錄從點 (i,j) 向右最大能延伸的長度。
然后,我們發現,僅僅做出預處理是不夠的,
因為,l[i][j] 和 r[i][j] 的值都各自取決於 l[i-1][j] 和 r[i-1][j]。(因為為保證成為一個矩形,l[i][j] 不能超過 l[i-1][j],r 同理)
所以枚舉點對 l 和 r 進行更新,對 l[i][j] 與 l[i-1][j] 取 min,r 同理。
這里可以合並求解與更新,每個點更新完之后順便算出這個點懸線的矩形面積即可。

1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 const int N=101,M=101; 5 int l[N][M],r[N][M],h[N][M],c[N][M],n,m; 6 int max(int,int),min(int,int); 7 void begin(); 8 int main(){ 9 int ans=0,x,y,tmp; 10 scanf("%d %d",&n,&m); 11 for (int i=1;i<=n;i++) 12 for (int j=1;j<=m;j++) 13 scanf("%d",&c[i][j]); 14 begin(); 15 for (int i=1;i<=n;i++) 16 for (int j=1;j<=m;j++){ 17 if (c[i][j]==0) 18 l[i][j]=0; 19 else l[i][j]=l[i][j-1]+1;//l 20 if (c[i][j]==0) 21 h[i][j]=0; 22 else h[i][j]=h[i-1][j]+1;//h 23 if (c[i][m-j+1]==0) 24 r[i][m-j+1]=0; 25 else r[i][m-j+1]=r[i][m-j+2]+1;//r 26 } 27 for (int i=1;i<=n;i++) 28 for (int j=1;j<=m;j++){ 29 if (h[i][j]>1){ 30 l[i][j]=min(l[i][j],l[i-1][j]); 31 r[i][j]=min(r[i][j],r[i-1][j]); 32 } 33 ans=max(ans,h[i][j]*(l[i][j]+r[i][j]-1)); 34 } 35 printf("%d",ans); 36 return 0; 37 } 38 void begin(){ 39 for (int i=1;i<=n;i++){ 40 l[i][0]=0; 41 r[i][m+1]=0; 42 } 43 for (int i=1;i<=m;i++) 44 h[0][i]=0; 45 } 46 int max(int x,int y){ 47 return x>y?x:y; 48 } 49 int min(int x,int y){ 50 return x<y?x:y; 51 }
例題:棋盤制作