欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[codevs1159]最大全零子矩阵

程序员文章站 2022-07-12 09:22:12
...

传送门←

先DP处理出每点向上最多扩展出的0的个数
再用二维单调栈处理最大矩形
其实就是对每一行跑一遍单调栈……

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
const int MAXN = 2000 + 50;
int map[MAXN][MAXN],f[MAXN][MAXN],dp[MAXN][MAXN];
int n,ans;
struct zt
{
    int h,l,w;
};
stack <zt> q;
void solve(int k)
{
    for(int i = 1;i <= n;i ++)
    {
        int h = dp[k][i];
        if(!q.empty())
        {
            zt u = q.top();
            zt p = u;
            if(u.h < h)
            {
                q.push((zt){h,i,i - p.l});//
                continue;
            }
            while(u.h >= h)
            {
                q.pop();
                ans = max(ans,max(u.h * (i - u.l + u.w - 1),h * (i - u.l + u.w)));//
                if(q.empty())
                {
                    ans = max(ans,h * (i - u.l + u.w));
                    break;
                }
                p = u;
                u = q.top();
            }
            q.push((zt){h,i,i - p.l + p.w});
        }
        else q.push((zt){h,i,1});
        ans = max(ans,h);
    }
    while(!q.empty())
    {
        zt u = q.top();
        q.pop();
        if(q.empty())
        {
            ans = max(ans,u.h * u.w);
            return;
        }
        zt x = q.top();
        ans = max(ans,x.h * (u.l - x.l + x.w));
    }
}
int main()
{
    scanf("%d",&n);
    for(int i = 1;i <= n;i ++)
    for(int j = 1;j <= n;j ++)
        scanf("%d",&map[i][j]);
    for(int i = 1;i <= n;i ++)
    {
        for(int j = 1;j <= n;j ++)
        dp[j][i] = !map[j][i] * (dp[j - 1][i] + 1);
    }
    for(int i = 1;i <= n;i ++)
    {
        solve(i);
    }
    printf("%d",ans);
}

tips:
1、明确宽度是否包括端点
2、宽度标志着该元素栈前元素实际位置→该元素位置,就是包括所有该元素前因不满足单调性而被弹出的元素宽度(栈为单调递增栈,故前面不满足弹出的元素一定是高度大了的,所以一定可以按照当前高度计算为矩形);
3、思路要清楚……至少要想清楚自己在打什么……OTZ