题面

小渊很懒,给你各个位置的高度,让你画立体图。

思路

首先,根据题单名称,我们可以知道要模拟。

1. 首先,当然也是本题最难的点,就是方块之间的前后视觉遮挡问题。

显然,对于斜二测画法的立体图,后面靠左的区域会被前者覆盖。那么我们自然会发现,从前往后画,覆盖问题会变得很复杂(不过也不是不能做)。

所以,我们不妨试试从俯视视角的左上角开始画。

我们以一个方块为一个单位开始画图。这里我们定义一个char二维数组来存储一个方块,并用题给的.符号来表示空区域。

char[][] one = {
            "..+---+".toCharArray(),
            "./   /|".toCharArray(),
            "+---+ |".toCharArray(),
            "|   | +".toCharArray(),
            "|   |/.".toCharArray(),
            "+---+..".toCharArray()
    };

然后,对于每一个新加入的方块,我们只要对one进行行列的遍历,如果不为.,就将前者对应位置覆盖。

2. 其次是定位的问题。

每个方块的大小是6 x 7,格子的数目也给出了范围,此处我们可以开一个存储数据的容量为500 x 500的数组(其实是随便输的,可能还不满足最大的容量,只能说测试数据不够全面,反正开大一点就好啦~),那么下角的点坐标就为(499, 499)

好的,那我们先拿几个图来推一下坐标的式子。

此处定义每个格子的坐标为(i, j, h)

注:为了更加形象一点,我就直接定义h下标从1开始,而ij仍从0开始。

image

对于左下角的高度为1的方块(即坐标为(m - 1, 0, 1)的方块),他的左上顶点位于(494, 0)

image

对于(m - 2, 1, 1)的方块,他的左上顶点位于(492, 2)

可见对于横纵坐标的改动,会有以2为倍数的改变,在高度为1时,我们可以推出下面的坐标式子:

(494 - 2(m - i - 1), 4j + 2(m - i - 1))

高度变化对坐标的影响是显而易见的。每当高度加1,横坐标会减少3(不能理解的话可以对照一下题面中两个方块上下相邻的图)。因此我们完善一下式子如下:

(497 - 2(m - i - 1) - 3h, 4j + 2(m - i - 1))

然后我们只需从俯视视角的左上角开始循环添加方块就ok了。

3. 输出问题 在每次添加方格的时候,我们可以记录一下上区间和右区间,上区间就是所有左上顶点的纵坐标最小值,右区间就是所有右上顶点横坐标最大值

ok,解毕。

AC(Java)代码

import java.util.*;

public class Main {

    static char[][] one = {
            "..+---+".toCharArray(),
            "./   /|".toCharArray(),
            "+---+ |".toCharArray(),
            "|   | +".toCharArray(),
            "|   |/.".toCharArray(),
            "+---+..".toCharArray()
    };

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        char[][] ans = new char[500][500]; //开数组
        for(int i=0;i<500;i++) for(int j=0;j<500;j++) ans[i][j] = '.'; //空位置填上占位符"."
        int m = scanner.nextInt(), n = scanner.nextInt();
        int[][] height = new int[m][n];
        for(int i=0;i<m;i++) for(int j=0;j<n;j++) height[i][j] = scanner.nextInt();
        int top = 500, right = 0;
        for(int i=0;i<m;i++) for(int j=0;j<n;j++) for(int h=1;h<=height[i][j];h++){
            //从左上角画起,存到数组底部,到时候记录最高和最右的位置即可
            int startI = 497 - 2 * (m - i - 1) - 3 * h, startJ = 4 * j + 2 * (m - i - 1);
            top = Math.min(top, startI);
            right = Math.max(right, startJ + 6);
            for(int p=0;p<6;p++) for(int q=0;q<7;q++){
                if(one[p][q] != '.') ans[startI + p][startJ + q] = one[p][q];
            }
        }
        for(int i=top;i<=499;i++) {
            for(int j=0;j<=right;j++) System.out.print(ans[i][j]);
            System.out.println();
        }
    }
}

随手转了一下cpp (update 22.12.12)

AC(cpp)代码

#include <bits/stdc++.h>

using namespace std;

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

char ans[500][500]; //开数组
int height[52][52];

int main() {
    for (int i = 0; i < 500; i++) for (int j = 0; j < 500; j++) ans[i][j] = '.'; //空位置填上占位符"."
    int m, n;
    scanf("%d %d", &m, &n);
    for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) scanf("%d", &height[i][j]);
    int top = 500, right = 0;
    for (int i = 0; i < m; i++)
        for (int j = 0; j < n; j++)
            for (int h = 1; h <= height[i][j]; h++) {
                //从左上角画起,存到数组底部,到时候记录最高和最右的位置即可
                int startI = 497 - 2 * (m - i - 1) - 3 * h, startJ = 4 * j + 2 * (m - i - 1);
                top = min(top, startI);
                right = max(right, startJ + 6);
                for (int p = 0; p < 6; p++) 
                    for (int q = 0; q < 7; q++) {
                        if (one[p][q] != '.') ans[startI + p][startJ + q] = one[p][q];
                    }
            }
    for (int i = top; i <= 499; i++) {
        for (int j = 0; j <= right; j++) printf("%c", ans[i][j]);
        printf("\n");
    }
}

0 条评论

目前还没有评论...