悬线法

使用 \(dp\) \(O(n*m)\) 解决矩阵最大面积问题。

两种解法,一种直接抄板子,但是需要将图抽象成为二维平面上,一些点固定可选,一些点固定不可选。换句话说,对于一个 \(01\) 矩阵,找出一个面积最大的矩形使得这个矩形内所有点都是 \(1\)

另一种解法,悬线找出每个节点可以向上/下扩展的最大长度,然后问题就转化成为了求解一个区间长度乘以区间最小值的最大值这题

题目1

解法一:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define endl '\n'
const int N=2e3+5;
const int mod=998244353;
short A[N*2][N],l[N*2][N],r[N*2][N],u[N*2][N];
void solve()
{
    int n,m;cin>>n>>m;
    memset(A,0,sizeof A);
    memset(l,0,sizeof l);
    memset(r,0,sizeof r);
    memset(u,0,sizeof u);

    //图转化
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>A[(i-1)*2+1][j];
    n=n*2;
    for(int j=1;j<=m;j++)
    {
        for(int i=1;i<=n;i+=2)
        {
            if(A[i][j]>A[i+2][j]) A[i+1][j]=0;
            else A[i+1][j]=1;
        }
    }

    //固定板子
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j])
                l[i][j]=l[i][j-1]+1;

    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            if(A[i][j])
                r[i][j]=r[i][j+1]+1;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j]) 
            {
                u[i][j]=u[i-1][j]+1;
                if(A[i-1][j]) l[i][j]=min(l[i][j],l[i-1][j]),r[i][j]=min(r[i][j],r[i-1][j]);
                ans=max(ans, (int)(r[i][j]+l[i][j]-1)*(int)(u[i][j]+1)/2 );
            }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

解法二:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=2e3+5;
const int mod=998244353;
int a[N][N],b[N][N];
void solve()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int j=1;j<=m;j++)
    {
        int ls=1;
        for(int i=1;i<=n;i++)
        {
            if(a[i-1][j]>a[i][j]) 
            {
                for(int l=i-1;l>=ls;l--) b[l][j]=(i-1)-l+1;
                ls=i;
            }
        }
        for(int l=n;l>=ls;l--) b[l][j]=n-l+1;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        stack<pii>s;
        s.push({0,0});
        for(int j=1;j<=m;j++)
        {
            while(s.top().first>=b[i][j])
            {  
                int w=s.top().first;
                s.pop();                
                ans=max(ans,(j-s.top().second-1)*w);
            }
            s.push({b[i][j],j});
        }
        while(s.size()!=1)
        {
            int w=s.top().first;
            s.pop();        
            ans=max(ans,(m-s.top().second)*w);
        }
    }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

题目2

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=4e3+5;
const int mod=998244353;
short a[N][N],A[N][N],l[N][N],r[N][N],u[N][N];
void solve()
{
    int n,m;cin>>n>>m;
    n*=2,m*=2;
    for(int i=1;i<=n;i+=2)
        for(int j=1;j<=m;j+=2)
            cin>>a[i][j];
    
    //图转化
    for(int i=1;i<=n;i+=2)
        for(int j=1;j<=m;j+=2)
        {
            A[i][j]=1;
            if(a[i][j]!=a[i+2][j]) A[i+1][j]=1;
            if(a[i][j]!=a[i][j+2]) A[i][j+1]=1;
        }

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(i%2==0&&j%2==0) A[i][j]=1;
    
    //板子
    int ans=0,ans1=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j])
                l[i][j]=l[i][j-1]+1;

    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            if(A[i][j])
                r[i][j]=r[i][j+1]+1;

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(A[i][j]) 
            {
                u[i][j]=u[i-1][j]+1;
                if(A[i-1][j]) l[i][j]=min(l[i][j],l[i-1][j]),r[i][j]=min(r[i][j],r[i-1][j]);
                ans=max(ans, (r[i][j]+l[i][j])/2*((u[i][j]+1)/2) );
                ans1=max(ans1,min((r[i][j]+l[i][j])/2,((u[i][j]+1)/2))*min((r[i][j]+l[i][j])/2,((u[i][j]+1)/2)));
            }
        }
    }
    cout<<ans1<<endl<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T=1;//cin>>T;
    while(T--) solve();
    return 0;
}
posted @ 2024-07-09 23:18  mhw-mathcode  阅读(70)  评论(0)    收藏  举报