sgu-250 Constructive Plan

59 篇文章 1 订阅
9 篇文章 0 订阅
题目大意:

给你一个 NM {0,1} 矩阵,然后只有为 0 的地方可以可用,然后要你找出一个最大的C,输出所占大小,并且在原图中把所占的地方改成 8 ,然后输出新的图。
PS:C的定义就是从上到下三个大小相邻且不为 0 的矩形,左边界需要对齐,并且上面和下面的矩形的右边界都要大于中间的矩形的右边界。

解题思路:

这道题我只想出了O(N3logN)的做法,虽然可以过,但是我写到一半写错了,然后偶然间看到了翱犇的代码,数了一下发现只有 3 个循环,”卧槽,N3,我于是赶快去膜拜了一下”。
O(N3logN) 的算法在这里我就不再赘述了,网上估计可以找得到,我还是讲一下 O(N3) 的算法吧。
 
First:
我们用 F[i][l][r] 表示以第 i 行,第l列和第 l+r1 列,为下边界的矩形最大的面积。如图:
这里写图片描述

Second:
然后我们令 G[i][l][r] 表示中间矩形以第 i 行,第l列和第 l+r1 列,为下边界时前两个矩形的最大面积和。如图:
这里写图片描述
那么显然 G[i][l][r] 转移方程为(当第 i 行第l列到第 l+r1 列都为 0 则为下式,否则为0)
G[i][l][r]=max(G[i1][l][r]+r,r+max(F[i1][l][k],k>r))
显然 max(F[i1][l][k],k>r) 可以再循环中用一个变量记录更新以达到 O(1)
Thrid:
H[i][l][r] 表示最下面的矩形以第 i 行,第l列和第 l+r1 列,为下边界时的最大答案。如图:
这里写图片描述
那么同 G 的计算类似,H[i][l][r]转移方程为(当第 i 行第l列到第 l+r1 列都为 0 则为下式,否则为0)
H[i][l][r]=max(H[i1][l][r]+r,r+max(G[i1][l][k],k<r))
然后这道题目就解决了。
输出就简单了

AC代码:

说明:本人由于太弱,边看翱犇的代码边学的题解,然后一不小心就写得和翱犇差不多了 QAQ

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>

using namespace std;

int n,m;
int ch[200][200]={{0}};
short top[200][200][200]={{{0}}};
short F[200][200][200]={{{0}}};
short G[200][200][200]={{{0}}};
short H[200][200][200]={{{0}}};
int area=0;
int ai=0,al=0,ar=0;

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&ch[i][j]);
            top[i][j][1]=(short)(ch[i][j]^1)*(top[i-1][j][1]+1);
        }
    for(int i=n;i>=1;i--)
        for(int j=m;j>=1;j--)
        {
            if(ch[i][j]==1) continue;
            for(int k=2;k+j-1<=m && ch[i][k+j-1]==0;k++)
            {
                top[i][j][k]=min(top[i][j][1],top[i][j+1][k-1]);
                F[i][j][k]=top[i][j][k]*k;
            }
        }

    for(int i=2;i<=n;i++)
        for(int j=m;j>=1;j--)
        {
            if(ch[i][j]==1) continue;
            int k;
            for(k=1;k+j-1<=m && ch[i][k+j-1]==0;k++);k--;
            int Max=0;
            for(int r=m-j+1;r>k;r--)
                Max=max((int)F[i-1][j][r],Max);
            for(int r=k;r>=1;r--)
            {
                if(G[i-1][j][r]>0) G[i][j][r]=G[i-1][j][r]+r;
                if(Max>0) G[i][j][r]=max((short)(Max+r),G[i][j][r]);
                Max=max((int)F[i-1][j][r],Max);
            }
        }
    for(int i=2;i<=n;i++)
        for(int j=m;j>=1;j--)
        {
            if(ch[i][j]==1) continue;
            int Max=0;
            for(int k=1;k+j-1<=m && ch[i][k+j-1]==0;k++)
            {
                H[i][j][k]=max((H[i-1][j][k]>0)*(H[i-1][j][k]+k),(Max>0)*(Max+k));
                Max=max((int)G[i-1][j][k],Max);
                if(H[i][j][k]>area)
                {
                    area=H[i][j][k];
                    ai=i,al=j,ar=k;
                }
            }
        }
    if(area<5) cout<<-1<<endl;
    else
    {
        cout<<area<<endl;
        for(;H[ai-1][al][ar]+ar==H[ai][al][ar];ai--)
            for(int i=1;i<=ar;i++)
                ch[ai][al+i-1]=8; 
        for(int r=1;r<=ar;r++)
            if(G[ai-1][al][r]+ar==H[ai][al][ar])
            {
                for(int k=1;k<=ar;k++)
                    ch[ai][al+k-1]=8;
                ar=r;ai--;break;
            }
        for(;G[ai-1][al][ar]+ar==G[ai][al][ar];ai--)
            for(int i=1;i<=ar;i++)
                ch[ai][al+i-1]=8; 
        for(int r=ar+1;al+r-1<=m;r++)
            if(F[ai-1][al][r]+ar==G[ai][al][ar])
            {
                for(int k=1;k<=ar;k++)
                    ch[ai][al+k-1]=8;
                ar=r;ai--;break;
            }
        for(;F[ai][al][ar]>0;ai--)
            for(int i=1;i<=ar;i++)
                ch[ai][al+i-1]=8;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                printf("%d ",ch[i][j]);
            puts("");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值