2013-11-11 09:14:05Morris

[ZJ][單調堆] b123 最大矩形 (Area)

內容 :

輸入說明 :

輸入檔第一行有兩個整數,依序為M 和N, M≦200, N≦200;接下來的M 行中,每一行有N 個0 或1 的數字。這N 個數字彼此間用一個空白隔開。

輸出說明 :

請將最大矩形空地面積寫出至輸出檔。
範例輸入 : 
4 5
0 0 1 1 0
0 1 1 1 1
0 1 1 1 1
0 0 1 0 0

範例輸出 :

8

提示 :

出處 :

95北市資訊學科能力競賽



線性時間 O(NM) 完成。

紀錄每一列的向左拓展最寬為何,然後對於每一列(假設它是矩形的最右側的邊上)找到最大矩形。


#include <stdio.h>
#include <stack>
#include <algorithm>
using namespace std;
int solve(int n, int h[]) {
    int ret = 0;
    int i, height;
    stack< pair<int, int> > stk;// <height, position>
    pair<int, int> e;
    stk.push(make_pair(-1, 0));
    h[n] = 0;// visual height.
    for(i = 0; i <= n; i++) {
        height = h[i];
        e = make_pair(height, i);
        while(height < stk.top().first) {
            e = stk.top(), stk.pop();
            ret = max(ret, (i - e.second) * e.first);
        }
        if(height > stk.top().first)
            stk.push(make_pair(height, e.second));
    }
    return ret;
}    
int n, m, h[1005], i, j;
int g[1005][1005];
int main() {
    while(scanf("%d %d", &n, &m) == 2) {
        for(i = 0; i < n; i++) {
            for(j = 0; j < m; j++) {
                scanf("%d", &g[i][j]);
            }
        }
        for(i = 0; i < n; i++) {
            int sum = 0;
            for(j = 0; j < m; j++) {
                sum += g[i][j];
                if(g[i][j] == 0)    
                    sum = 0;
                g[i][j] = sum;
            }
        }
        int ret = 0;
        for(i = 0; i < m; i++) {
            for(j = 0; j < n; j++)
                h[j] = g[j][i];
            ret = max(ret, solve(n, h));
        }
        printf("%d\n", ret);
    }
    return 0;
}