poj3494(求最大全1子矩陣)

點我

這題和最大子矩陣和都是用了壓行的思想把多行壓成 一行,降維後當成1維的處理。

區別是這個是枚舉底行

 

先思考這樣一個問題,如何求一個數組{3 4 5 2 4}圍成的最大面積。

對任意一個位置i,我們需要找到其左右邊第一個小於arr[i]的數的位置p1,p2,則位置i對應的面積是(p2 - p1 - 1)* arr[i]

需要一個輔助棧,壓入彈出規則如下:(注意只壓入下標)

1. 若當前數 arr[i] 大於或等於棧頂數arr[j],壓入當前數的下標i;

2.否則,彈出棧頂數j。此時棧頂數爲k,繼續判斷。

 

只在情況2中計算想要的面積。對彈出的棧頂數j,其右邊第一個比他小的數爲arr[i], 其左邊第一個比他小的數爲arr[k]. 則對j來說,其對應的面積爲(i - k - 1)* arr[j]

我給up[0]和up[m+1]分別設置爲-1,目的是讓嗎每個元素出棧後,任然存在棧頂元素,作爲tmp元素能拓展到的最左,和每個元素都能出棧,保證每個元素對應的柱子都能計算到。

#include<stdio.h>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
const int inf=0x3f3f3f3f;
const int maxn=2e3+10;
int d[4][2]={1,0,-1,0,0,1,0,-1};
int n,m;
int up[maxn],mp[maxn][maxn];
stack<int>sta;
int main(){
    while(scanf("%d",&n)!=EOF){
        memset(up,0,sizeof(up));
        int ans=0;
        scanf("%d",&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&(mp[i][j]));
        up[0]=up[m+1]=-1;
        for(int i=1;i<=n;i++) {
            for (int j=1;j<=m;j++)
                up[j]=(mp[i][j]==0)?0:(up[j]+1);
            while(!sta.empty()) sta.pop();
            for(int j=0;j<=m+1;j++){
                while(!sta.empty()&&up[sta.top()]>up[j])
                {
                    int tmp=sta.top();sta.pop();
                    ans=max(ans,up[tmp]*(j-sta.top()-1));
                }
                sta.push(j);
            }

        }
        cout<<ans<<endl;
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章