C++题解:[NOIP2008pj]立体图

      目录

题目 

题解


题目 

小渊是个聪明的孩子,他经常会给周围的小朋友们将写自己认为有趣的内容。最近,他准备给小朋友们讲解立体图,请你帮他画出立体图。

小渊有一块面积为 m×n 的矩形区域,上面有 m×n 个边长为 1 的格子,每个格子上堆了一些同样大小的积木(积木的长宽高都是 1),小渊想请你打印出这些格子的立体图。

我们定义每个积木为如下格式,并且不会做任何翻转旋转,只会严格以这一种形式摆放:

21.png.jpg

每个顶点用 11 个加号 + 表示,长用 33 个  表示,宽用 11 个 / 表示,高用两个 | 表示。

字符 +,,/,| 的 ASCII 码分别为 43,45,47,124。

字符 . (ASCII 码 46)需要作为背景输出,即立体图里的空白部分需要用 . 来代替。

立体图的画法如下面的规则:

若两块积木左右相邻,图示为:

22.png.jpg

若两块积木上下相邻,图示为:

23.png.jpg

若两块积木前后相邻,图示为:

24.png.jpg

立体图中,定义位于第 (m,1) 的格子(即第 m 行第 1 列的格子)上面自底向上的第一块积木(即最下面的一块积木)的左下角顶点为整张图最左下角的点。

输入格式

输入文件第一行有用空格隔开的两个整数 m 和 n,表示有 m×n 个格子。 

接下来的 m 行,是一个 m×n 的矩阵,每行有 n 个用空格隔开的整数,其中第 ii 行第 jj 列上的整数表示第 i 行第 j 列的格子上摞有多少个积木(1≤每个格子上的积木数≤100)。

输出格式

输出文件中包含题目要求的立体图,是一个 K 行 L 列的字符矩阵,其中 K 和 L 表示最少需要 K 行 L 列才能按规定输出立体图。

数据范围

1≤m,n≤50

输入样例:

3 4
2 2 1 2
2 2 1 1
3 2 1 2

输出样例:

......+---+---+...+---+
..+---+  /   /|../   /|
./   /|-+---+ |.+---+ |
+---+ |/   /| +-|   | +
|   | +---+ |/+---+ |/|
|   |/   /| +/   /|-+ |
+---+---+ |/+---+ |/| +
|   |   | +-|   | + |/.
|   |   |/  |   |/| +..
+---+---+---+---+ |/...
|   |   |   |   | +....
|   |   |   |   |/.....
+---+---+---+---+......




题解:

知识点:字符串处理、模拟、坐标变换

分析:

首先将一个小正方体的投影画出来:

char box[6][8] = {
    "..+---+",
    "./   /|",
    "+---+ |",
    "|   | +",
    "|   |/.",
    "+---+.."
};

然后为了正确处理遮挡关系,按照从后到前、从左到右、从下到上的顺序画每个小正方体即可。

两个坐标系如下所示,我们将最靠左、前、下的小立方体,和二维坐标系中左下角的点(499,0)对齐。

QQ图片20190824205539.png

然后观察可以发现二者的映射关系:设小立方体在 (x,y,z)( ,即第 x 行第 y 列第 z 层, 则对于投影后的坐标而言:

  • 横坐标:z 每变1,横坐标变3,x 每变1,横坐标变2;
  • 纵坐标:x 每变1,总坐标变2,y 每变1,纵坐标变4

因此投影之后的左下角坐标是:

  • 横坐标是 499−3z−2(n−1−x)
  • 纵坐标是 2(n−1−x)+4y

接下来还需要确定投影之后的二维平面的范围。

最后将二维投影平面的范围内的部分输出即可。

这题好造孽

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define _for(i,a,b) for (int i=(a);i<(b);i++)
using namespace std;
const int N=500;
int h[N][N];
char g[N][N],box[6][8]={//预处理,注意是box[6][8],不是box[6][7],因为每个字符串末还有占位符
    "..+---+",
    "./   /|",
    "+---+ |",
    "|   | +",
    "|   |/.",
    "+---+.."
};
int main(){
    int n,m,up=N,right=0;
    scanf("%d%d",&n,&m);
    _for(i,0,n){
        _for(j,0,m){
            scanf("%d",&h[i][j]);
        }
    }
    _for(i,0,N){//预处理
        _for(j,0,N){
            g[i][j]='.';
        }
    }
    _for(x,0,n){
        _for(y,0,m){
            _for(z,0,h[x][y]){
                int X=499-3*z-((n-1-x)<<1),Y=4*y+((n-1-x)<<1);//见解析(<<1是*2的意思)
                up=min(up,X-5);//整个二维立方体上边界
                right=max(right,Y+6);//右边界
                _for(a,0,6){//填充单位二维立方体
                    _for(b,0,7){
                        if (box[a][b]!='.'){
                            g[X-5+a][Y+b]=box[a][b];//自己画图理解
                        }
                    }
                }
            }
        }
    }
    _for(i,up,N){//输出
        _for(j,0,right+1){
            putchar(g[i][j]);
        }
        puts("");
    }
    return 0;
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值