题解:P6265 [COCI 2014/2015 #3] SILUETA

P6265矩形叠放题解

P6265

题目大意

n n n 个矩形叠放,求它们的周长,并输出它们的轮廓。
注意:左右两边必须以轮廓开始且输出的是轮廓的周长(并不是 # 的总和)。

思路

直接的修改是最简单的,如果你每一次都算出当次的现状,是很复杂的,我们考虑先修改,后面再决定哪些是有用的。
b i , j b_{i,j} bi,j 为第 i i i 行第 j j j 列的元素,且 0 0 0 为空, 1 1 1 为轮廓。
所以写出如下代码:

    for(int i=1;i<=n;i++){
        cin>>l>>r>>h;
        r--;
        H=max(H,h);
        L=min(L,l);
        R=max(R,r);
        for(int i=1;i<=h;i++)b[i][l]=b[i][r]=1;
        for(int j=l;j<=r;j++)b[h][j]=1;
    }

注意,此时维护 H H H L L L R R R 的值,是为了方便后面的修改与输出,至于为什么 r r r 要减少可以看样例(数一下修改的范围可知,每次只修改 [ l , r − 1 ] [l,r-1] [l,r1] 区间内的)。
接下来到了最难的地方,我们如何知道那些轮廓是无用的呢?
发现个必然的事情:对于所有不需要的轮廓,一定在一些需要的轮廓的包围中。
所以有以下方法:对于每一列,从高到低依次扫描,扫到 # 退出把以自己为中心的八个方向一共九个打上标记,用 x x x 数组维护。因为这种方法就像雨落下来一样,且我也没听说过这种方法,所以我叫它暴雨法。此时,就有所有不需要的轮廓,设它在的位置为 i , j i,j i,j x i , j ≠ 1 x_{i,j}\ne 1 xi,j=1 很好理解,你都在其他轮廓的包含里,自然不可能会被赋值。
接下来我们思考另一个问题:如何统计周长?
还是采用暴雨法,对于 i , j i,j i,j 统计 b i − 1 , j + b i + 1 , j + b i , j − 1 + b i , j + 1 b_{i-1,j}+b_{i+1,j}+b_{i,j-1}+b_{i,j+1} bi1,j+bi+1,j+bi,j1+bi,j+1 的值,退出方法与上述无异,所以可以合一起写。
代码:

    for(int i=L-1;i<=R+1;i++)for(int j=H+1;j>=1;j--){
        if(b[j][i])break;
        x[j-1][i-1]=x[j-1][i]=x[j-1][i+1]=x[j][i-1]=x[j][i]=x[j][i+1]=x[j+1][i-1]=x[j+1][i]=x[j+1][i+1]=1;
        sum+=b[j-1][i]+b[j+1][i]+b[j][i-1]+b[j][i+1];
    }

接下来就是输出,只有满足本身为 # 且被复制的才会输出 # 否则不会。
代码:

    cout<<sum<<"\n";
    for(int i=H;i>=1;i--){
        for(int j=L;j<=R;j++)cout<<(b[i][j]&&x[i][j]?'#':'.');
        cout<<"\n";
    }
    for(int i=L;i<=R;i++)cout<<'*';

注意事项

  • 注意雨流的方向(不能从左向右流,只能从上到下)。
  • 注意起始位置(不能让边界没扫出来)。
  • 注意雨流的顺序,是从上往下的(你回到过去不就从下往上了吗)。

代码

#include<bits/stdc++.h>
using namespace std;
int n,L=1005,R,l,r,h,H,z[1005],sum;
bool b[1005][1005],x[1005][1005];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>l>>r>>h;
        r--;
        H=max(H,h);
        L=min(L,l);
        R=max(R,r);
        for(int i=1;i<=h;i++)b[i][l]=b[i][r]=1;
        for(int j=l;j<=r;j++)b[h][j]=1;
    }
    for(int i=L-1;i<=R+1;i++)for(int j=H+1;j>=1;j--){
        if(b[j][i])break;
        x[j-1][i-1]=x[j-1][i]=x[j-1][i+1]=x[j][i-1]=x[j][i]=x[j][i+1]=x[j+1][i-1]=x[j+1][i]=x[j+1][i+1]=1;
        sum+=b[j-1][i]+b[j+1][i]+b[j][i-1]+b[j][i+1];
    }
    cout<<sum<<"\n";
    for(int i=H;i>=1;i--){
        for(int j=L;j<=R;j++)cout<<(b[i][j]&&x[i][j]?'#':'.');
        cout<<"\n";
    }
    for(int i=L;i<=R;i++)cout<<'*';
    return 0;
}
//BluePoch-1999
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值